diff --git a/package.json b/package.json index 52f299190..0fe33c141 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,9 @@ "@noble/hashes": "1.6.0", "@scure/base": "1.2.1", "@scure/starknet": "1.1.0", + "@wallet-standard/features": "^1.1.0", "abi-wan-kanabi": "2.2.4", + "@starknet-io/get-starknet/wallet-standard/features": "^5.0.0", "isows": "^1.0.6", "lossless-json": "^4.0.1", "pako": "^2.0.4", diff --git a/src/index.ts b/src/index.ts index 44229d0d9..0c077f622 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,7 @@ export * from './utils/contract'; export * from './utils/transactionReceipt/transactionReceipt'; export * from './utils/units'; export * as wallet from './wallet/connect'; +export * as walletV5 from './wallet/connectV5'; export * from './global/config'; export * from './global/logger'; export * from './global/logger.type'; diff --git a/src/wallet/accountV5.ts b/src/wallet/accountV5.ts new file mode 100644 index 000000000..63f53ee05 --- /dev/null +++ b/src/wallet/accountV5.ts @@ -0,0 +1,183 @@ +import type { + AddStarknetChainParameters, + Signature, + WatchAssetParameters, +} from 'starknet-types-08'; + +import type { WalletWithStarknetFeatures } from '@starknet-io/get-starknet/wallet-standard/features'; +import type { StandardEventsChangeProperties } from '@wallet-standard/features'; + +import { Account, AccountInterface } from '../account'; +import { StarknetChainId } from '../global/constants'; +import { ProviderInterface } from '../provider'; +import { + AllowArray, + CairoVersion, + Call, + CompiledSierra, + DeclareContractPayload, + MultiDeployContractResponse, + ProviderOptions, + TypedData, + UniversalDeployerContractPayload, +} from '../types'; +import { extractContractHashes } from '../utils/contract'; +import { stringify } from '../utils/json'; +import { buildUDCCall } from '../utils/transaction'; +import { + addDeclareTransaction, + addInvokeTransaction, + addStarknetChain, + getPermissions, + subscribeWalletEvent, + requestAccounts, + signMessage, + switchStarknetChain, + watchAsset, +} from './connectV5'; + +/** + * WalletAccountV5 class. + * This class is used to create a wallet account that can be used to interact with a Starknet wallet browser extension, using get-starknet v5. + */ +export class WalletAccountV5 extends Account implements AccountInterface { + public walletProvider: WalletWithStarknetFeatures; + + /** + * The function to use to unsubscribe from the wallet events. + * To call before the instance is deleted. + */ + private unsubscribe: () => void; + + constructor( + /* Node that will be used to READ Starknet */ + providerOrOptions: ProviderOptions | ProviderInterface, + /* the get-starknet v5 wallet that will WRITE Starknet */ + walletProvider: WalletWithStarknetFeatures, + /* Optional. To use when address is known */ + address: string, + /* Optional cairo version of the account ("0" | "1") */ + cairoVersion?: CairoVersion + ) { + super(providerOrOptions, address, '', cairoVersion); // At this point unknown address + this.walletProvider = walletProvider; + + // Update Address/network on change + this.unsubscribe = this.walletProvider.features['standard:events'].on( + 'change', + (change: StandardEventsChangeProperties) => { + if (!change.accounts?.length) return; + if (change.accounts[0].address) this.address = change.accounts[0].address; + if (change.accounts[0].chains) + this.channel.setChainId(change.accounts[0].chains[0].slice(9) as StarknetChainId); + } + ); + } + + /** + * WALLET EVENTS + */ + public onChange(callback: (change: StandardEventsChangeProperties) => void): void { + subscribeWalletEvent(this.walletProvider, callback); + } + + public unsubscribeChange(): void { + this.unsubscribe(); + } + + /** + * WALLET SPECIFIC METHODS + */ + public requestAccounts(silentMode = false) { + return requestAccounts(this.walletProvider, silentMode); + } + + public getPermissions() { + return getPermissions(this.walletProvider); + } + + public switchStarknetChain(chainId: StarknetChainId) { + return switchStarknetChain(this.walletProvider, chainId); + } + + public watchAsset(asset: WatchAssetParameters) { + return watchAsset(this.walletProvider, asset); + } + + public addStarknetChain(chain: AddStarknetChainParameters) { + return addStarknetChain(this.walletProvider, chain); + } + + /** + * ACCOUNT METHODS + */ + override execute(calls: AllowArray) { + const txCalls = [].concat(calls as any).map((it) => { + const { contractAddress, entrypoint, calldata } = it; + return { + contract_address: contractAddress, + entry_point: entrypoint, + calldata, + }; + }); + + const params = { + calls: txCalls, + }; + + return addInvokeTransaction(this.walletProvider, params); + } + + override declare(payload: DeclareContractPayload) { + const declareContractPayload = extractContractHashes(payload); + // DISCUSS: HOTFIX: Adapt Abi format + const pContract = payload.contract as CompiledSierra; + const cairo1Contract = { + ...pContract, + abi: stringify(pContract.abi), + }; + if (!declareContractPayload.compiledClassHash) { + throw Error('compiledClassHash is required'); + } + const params = { + compiled_class_hash: declareContractPayload.compiledClassHash, + contract_class: cairo1Contract, + }; + return addDeclareTransaction(this.walletProvider, params); + } + + override async deploy( + payload: UniversalDeployerContractPayload | UniversalDeployerContractPayload[] + ): Promise { + const { calls, addresses } = buildUDCCall(payload, this.address); + const invokeResponse = await this.execute(calls); + return { + ...invokeResponse, + contract_address: addresses, + }; + } + + override signMessage(typedData: TypedData): Promise { + return signMessage(this.walletProvider, typedData); + } + + static async connect( + provider: ProviderInterface, + walletProvider: WalletWithStarknetFeatures, + cairoVersion?: CairoVersion, + silentMode: boolean = false + ) { + const [accountAddress] = await requestAccounts(walletProvider, silentMode); + return new WalletAccountV5(provider, walletProvider, accountAddress, cairoVersion); + } + + static async connectSilent( + provider: ProviderInterface, + walletProvider: WalletWithStarknetFeatures, + cairoVersion?: CairoVersion + ) { + return WalletAccountV5.connect(provider, walletProvider, cairoVersion, true); + } + + // TODO: MISSING ESTIMATES +} diff --git a/src/wallet/connectV5.ts b/src/wallet/connectV5.ts new file mode 100644 index 000000000..241d31b3c --- /dev/null +++ b/src/wallet/connectV5.ts @@ -0,0 +1,181 @@ +import type { StandardEventsChangeProperties } from '@wallet-standard/features'; +import type { WalletWithStarknetFeatures } from 'getSnStandard/features'; +import { + type WatchAssetParameters, + type AddDeclareTransactionParameters, + type AddInvokeTransactionParameters, + type AddStarknetChainParameters, + type ChainId, + type TypedData, + type Permission, + type Address, + AddInvokeTransactionResult, + AddDeclareTransactionResult, + AccountDeploymentData, + Signature, + SpecVersion, +} from 'starknet-types-08'; + +/** + * Request Permission for wallet account, return addresses that are allowed by user + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {boolean} [silent_mode=false] false: request user interaction allowance. true: return only pre-allowed + * @returns {Address[]} allowed accounts addresses + */ +export function requestAccounts( + walletWSF: WalletWithStarknetFeatures, + silent_mode: boolean = false +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_requestAccounts', + params: { silent_mode }, + }); +} + +/** + * Request if DAPP is connected to wallet. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @returns {Permission[]} "accounts" if permission granted + */ +export function getPermissions(walletWSF: WalletWithStarknetFeatures): Promise { + return walletWSF.features['starknet:walletApi'].request({ type: 'wallet_getPermissions' }); +} + +/** + * Request adding an ERC20 Token to the Wallet List + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {WatchAssetParameters} asset description of the token to add. + * @returns {boolean} true if the token was added successfully + */ +export function watchAsset( + walletWSF: WalletWithStarknetFeatures, + asset: WatchAssetParameters +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_watchAsset', + params: asset, + }); +} + +/** + * Request adding custom Starknet chain + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {AddStarknetChainParameters} chain description of the chain to add. + * @returns {boolean} true if the chain was added successfully + */ +export function addStarknetChain( + walletWSF: WalletWithStarknetFeatures, + chain: AddStarknetChainParameters +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_addStarknetChain', + params: chain, + }); +} + +/** + * Request Wallet Network change + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {ChainId} chainId encoded name of the chain requested. + * @returns {boolean} true if the chain was changed successfully + */ +export function switchStarknetChain( + walletWSF: WalletWithStarknetFeatures, + chainId: ChainId +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_switchStarknetChain', + params: { chainId }, + }); +} + +/** + * Request the current chain ID from the wallet. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @returns {ChainId} The current Starknet chain ID. + */ +export function requestChainId(walletWSF: WalletWithStarknetFeatures): Promise { + return walletWSF.features['starknet:walletApi'].request({ type: 'wallet_requestChainId' }); +} + +/** + * Get deployment data for a contract. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @returns {AccountDeploymentData} The deployment data result. + */ +export function deploymentData( + walletWSF: WalletWithStarknetFeatures +): Promise { + return walletWSF.features['starknet:walletApi'].request({ type: 'wallet_deploymentData' }); +} + +/** + * Add an invoke transaction to the wallet. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {AddInvokeTransactionParameters} params The parameters required for the invoke transaction. + * @returns {AddInvokeTransactionResult} The result of adding the invoke transaction. + */ +export function addInvokeTransaction( + walletWSF: WalletWithStarknetFeatures, + params: AddInvokeTransactionParameters +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_addInvokeTransaction', + params, + }); +} + +/** + * Add a declare transaction to the wallet. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {AddDeclareTransactionParameters} params The parameters required for the declare transaction. + * @returns {AddDeclareTransactionResult} The result of adding the declare transaction. + */ +export function addDeclareTransaction( + walletWSF: WalletWithStarknetFeatures, + params: AddDeclareTransactionParameters +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_addDeclareTransaction', + params, + }); +} + +/** + * Sign typed data using the wallet. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {TypedData} typedData The typed data to sign. + * @returns {Signature} An array of signatures as strings. + */ +export function signMessage( + walletWSF: WalletWithStarknetFeatures, + typedData: TypedData +): Promise { + return walletWSF.features['starknet:walletApi'].request({ + type: 'wallet_signTypedData', + params: typedData, + }); +} + +/** + * Get the list of supported Wallet API specifications. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @returns {SpecVersion[]} An array of wallet API supported specification strings. + */ +export function supportedSpecs(walletWSF: WalletWithStarknetFeatures): Promise { + return walletWSF.features['starknet:walletApi'].request({ type: 'wallet_supportedSpecs' }); +} + +/** + * Attaches an event handler function for the changes of network and account. + * When the account/network are changed, the specified callback function will be called. + * @param {WalletWithStarknetFeatures} walletWSF - The get-starknet V5 wallet object to use. + * @param {StandardEventsChangeProperties} callback - The function to be called when the account/network are changed. + * @returns {() => void} function to execute to unsubscribe events. + */ +export function subscribeWalletEvent( + walletWSF: WalletWithStarknetFeatures, + callback: (change: StandardEventsChangeProperties) => void +): () => void { + return walletWSF.features['standard:events'].on('change', callback); +} diff --git a/src/wallet/index.ts b/src/wallet/index.ts index 362a768e5..7c4da69bf 100644 --- a/src/wallet/index.ts +++ b/src/wallet/index.ts @@ -1 +1,2 @@ export * from './account'; +export * from './accountV5'; diff --git a/www/docs/guides/pictures/SelectWallet.png b/www/docs/guides/pictures/SelectWallet.png deleted file mode 100644 index 0f3395cba..000000000 Binary files a/www/docs/guides/pictures/SelectWallet.png and /dev/null differ diff --git a/www/docs/guides/pictures/SelectWalletV4.png b/www/docs/guides/pictures/SelectWalletV4.png new file mode 100644 index 000000000..79a6726a8 Binary files /dev/null and b/www/docs/guides/pictures/SelectWalletV4.png differ diff --git a/www/docs/guides/pictures/SelectWalletV5.png b/www/docs/guides/pictures/SelectWalletV5.png new file mode 100644 index 000000000..0243346f7 Binary files /dev/null and b/www/docs/guides/pictures/SelectWalletV5.png differ diff --git a/www/docs/guides/pictures/WalletAccountArchitecture.png b/www/docs/guides/pictures/WalletAccountArchitecture.png index 0bc717d5a..bbe52e10f 100644 Binary files a/www/docs/guides/pictures/WalletAccountArchitecture.png and b/www/docs/guides/pictures/WalletAccountArchitecture.png differ diff --git a/www/docs/guides/walletAccount.md b/www/docs/guides/walletAccount.md index f274e6be2..329a92e9a 100644 --- a/www/docs/guides/walletAccount.md +++ b/www/docs/guides/walletAccount.md @@ -6,9 +6,9 @@ sidebar_position: 9 **Use wallets to sign transactions in your DAPP.** -The [`WalletAccount`](../API/classes/WalletAccount) class is similar to the regular [`Account`](../API/classes/Account) class, with the added ability to ask a browser wallet to sign and send transactions. Some other cool functionalities will be detailed hereunder. +The [`WalletAccount`](../API/classes/WalletAccountV5) class is similar to the regular [`Account`](../API/classes/Account) class, with the added ability to ask a Wallet (such as ArgentX, Braavos, etc...) to sign and send transactions. Some other cool functionalities will be detailed hereunder. -The private key of a `WalletAccount` is held in a browser wallet (such as ArgentX, Braavos, etc.), and any signature is managed by the wallet. With this approach DAPPs don't need to manage the security for any private key. +The private key of a `WalletAccount` is held in the Wallet, so any signature is managed by the wallet. With this approach DAPPs don't need to manage the security for any private key. :::caution This class functions only within the scope of a DAPP. It can't be used in a Node.js script. @@ -16,39 +16,49 @@ This class functions only within the scope of a DAPP. It can't be used in a Node ## Architecture +In your DAPP, you have to use the `get-starknet` library to select and interact with a wallet. + ![](./pictures/WalletAccountArchitecture.png) -When retrieving information from Starknet, a `WalletAccount` instance will read directly from the blockchain. That is why at the initialization of a `WalletAccount` a [`Provider`](../API/classes/Provider) instance is a required parameter, it will be used for all reading activities. +`get-starknet v4` is working only in desktop browsers. +`get-starknet v5` is working also in mobile browsers. +You can use the `WalletAccount` class with `get-starknet v4`, and the `WalletAccountV5` class with `get-starknet v5`. -If you want to write to Starknet the `WalletAccount` will ask the browser wallet to sign and send the transaction using the Starknet Wallet API to communicate. +## With get-starknet v5 -As several wallets can be installed in your browser, the `WalletAccount` needs the ID of one of the available wallets. You can ask `get-starknet` to display a list of available wallets and to provide as a response the identifier of the selected wallet, called a `Starknet Windows Object` (referred to as SWO in the rest of this guide). +When retrieving information from Starknet, a `WalletAccountV5` instance will read directly from the blockchain. That is why at the initialization of a `WalletAccountV5` a [`RpcProvider`](../API/classes/ProviderInterface) instance is a required parameter, it will be used for all reading activities. -## Select a Wallet +If you want to write to Starknet the `WalletAccountV5` will ask the wallet to sign and send the transaction using the Starknet Wallet API to communicate. -You can ask the `get-starknet` v4 library to display a list of wallets, then it will ask you to make a choice. It will return the SWO of the wallet the user selected. +As several wallets can be installed in your desktop/mobile, the `WalletAccountV5` needs the ID of one of the available wallets. You can ask `get-starknet v5` to provide a list of available wallets, and you have to select one of them, called a `WalletWithStarknetFeatures` Object. -Using the `get-starknet-core` v4 library you can create your own UI and logic to select the wallet. An example of DAPP using a custom UI: [**here**](https://github.com/PhilippeR26/Starknet-WalletAccount/blob/main/src/app/components/client/WalletHandle/SelectWallet.tsx), in the example you can select only the wallets compatible with the Starknet Wallet API. -![](./pictures/SelectWallet.png) +### Select a Wallet -Instantiating a new `WalletAccount`: +Using the `get-starknet/discovery v5` library you have to create your own UI and logic to select one of the available wallets. An example in a DAPP: [**here**](). In this example you can select only the wallets compatible with the Starknet Wallet API. +![](./pictures/SelectWalletV5.png) + +Instantiating a new `WalletAccountV5`: ```typescript -import { connect } from '@starknet-io/get-starknet'; // v4.0.3 min -import { WalletAccount, wallet } from 'starknet'; // v7.0.1 min +import { createStore, type Store } from '@starknet-io/get-starknet/discovery'; // v5.0.0 min +import { type WalletWithStarknetFeatures } from '@starknet-io/get-starknet/standard/features'; +import { WalletAccountV5, walletV5 } from 'starknet'; // v7.2.0 min const myFrontendProviderUrl = 'https://free-rpc.nethermind.io/sepolia-juno/v0_8'; -// standard UI to select a wallet: -const selectedWalletSWO = await connect({ modalMode: 'alwaysAsk', modalTheme: 'light' }); -const myWalletAccount = await WalletAccount.connect( +const store: Store = createStore(); +const walletsList: WalletWithStarknetFeatures[] = store.getWallets(); +// Create you own Component to select one of these wallets. +// Hereunder, selection of 2nd wallet of the list. +const selectedWallet: WalletWithStarknetFeatures = walletsList[1]; +const myWalletAccount: WalletAccountV5 = await WalletAccountV5.connect( { nodeUrl: myFrontendProviderUrl }, - selectedWalletSWO + selectedWallet ); ``` The wallet is connected to this blockchain to write in Starknet: ```typescript -const writeChainId = await wallet.requestChainId(myWalletAccount.walletProvider); +const writeChainId = await walletV5.requestChainId(myWalletAccount.walletProvider); ``` and to this blockchain to read Starknet: @@ -57,44 +67,77 @@ and to this blockchain to read Starknet: const readChainId = await myWalletAccount.getChainId(); ``` -## Use as an Account +### Subscription to events -Once a new `WalletAccount` is created, you can use all the power of Starknet.js, exactly as a with a normal `Account` instance, for example `myWalletAccount.execute(call)` or `myWalletAccount.signMessage(typedMessage)`: +You can subscribe to one event with `get-starknet v5`: + +`onChange`: Triggered each time you change the current account or the current network in the wallet. ```typescript -const claimCall = airdropContract.populate('claim_airdrop', { - amount: amount, - proof: proof, -}); -const resp = await myWalletAccount.execute(claimCall); +import type { StandardEventsChangeProperties } from "@wallet-standard/features"; +const addEvent = useCallback((change: StandardEventsChangeProperties) => { + console.log("Event detected", change.accounts); + if (change.accounts?.length) { + console.log("account event=", change.accounts[0].address); + setCurrentAccount(change.accounts[0].address); + console.log("network event=", change.accounts[0].chains[0]); + setCurrentChainId(change.accounts[0].chains[0].slice(9)); + } +}, []); +... +useEffect(() => { + console.log("Subscribe events..."); + selectedWalletAccountV5?.onChange(addEvent); + return () => { + console.log("Unsubscribe to events..."); + selectedWalletAccountV5?.unsubscribeChange(); +} +} +, [selectedWalletAccountV5, addEvent]); ``` -![](./pictures/executeTx.png) +## With get-starknet v4 + +The concept of Starknet reading/writing is the same when using `get-starknet v4` and the `WalletAccount` class. -## Use in a Contract instance +### Select a Wallet -You can connect a `WalletAccount` with a [`Contract`](../API/classes/Contract) instance. All reading actions are performed by the provider of the `WalletAccount`, and all writing actions (that need a signature) are performed by the browser wallet. +You can ask the `get-starknet v4` library to display a window with a list of wallets, then it will ask you to make a choice. It will return the `StarknetWindowObject` Object (referred to as SWO hereunder) of the wallet the user selected. +![](./pictures/SelectWalletV4.png) + +Instantiating a new `WalletAccount`: ```typescript -const lendContract = new Contract(contract.abi, contractAddress, myWalletAccount); -const qty = await lendContract.get_available_asset(addr); // use of the WalletAccount provider -const resp = await lendContract.process_lend_asset(addr); // use of the browser wallet +import { connect } from '@starknet-io/get-starknet'; // v4.0.3 min +import { WalletAccount, wallet } from 'starknet'; // v7.0.1 min +const myFrontendProviderUrl = 'https://free-rpc.nethermind.io/sepolia-juno/v0_8'; +// standard UI to select a wallet: +const selectedWalletSWO = await connect({ modalMode: 'alwaysAsk', modalTheme: 'light' }); +const myWalletAccount = await WalletAccount.connect( + { nodeUrl: myFrontendProviderUrl }, + selectedWalletSWO +); ``` -## Use as a Provider +:::tip +Using the `get-starknet-core` v4 library you can create your own UI and logic to select the wallet. An example of DAPP using a custom UI [**here**](https://github.com/PhilippeR26/Starknet-WalletAccount/blob/53514a5529c4aebe9e7c6331186e83b7a7310ce0/src/app/components/client/WalletHandle/SelectWallet.tsx), in this example you can select only the wallets compatible with the Starknet Wallet API. +::: -Your `WalletAccount` instance can be used as a provider: +The wallet is connected to this blockchain to write in Starknet: ```typescript -const bl = await myWalletAccount.getBlockNumber(); -// bl = 2374543 +const writeChainId = await wallet.requestChainId(myWalletAccount.walletProvider); ``` -You can use all the methods of the `Provider` class. Under the hood, the `WalletAccount` will use the RPC node that you indicated at its instantiation. +and to this blockchain to read Starknet: -## Subscription to events +```typescript +const readChainId = await myWalletAccount.getChainId(); +``` -You can subscribe to 2 events: +### Subscription to events + +You can subscribe to 2 events with `get-starknet v4`: - `accountsChanged`: Triggered each time you change the current account in the wallet. - `networkChanged`: Triggered each time you change the current network in the wallet. @@ -102,9 +145,9 @@ You can subscribe to 2 events: At each change of the network, both account and network events are emitted. At each change of the account, only the account event is emitted. -### Subscribe +#### Subscribe -#### accountsChanged +##### accountsChanged ```typescript const handleAccount: AccountChangeEventHandler = (accounts: string[] | undefined) => { @@ -116,18 +159,18 @@ const handleAccount: AccountChangeEventHandler = (accounts: string[] | undefined selectedWalletSWO.on('accountsChanged', handleAccount); ``` -#### networkChanged +##### networkChanged ```typescript const handleNetwork: NetworkChangeEventHandler = (chainId?: string, accounts?: string[]) => { if (!!chainId) { - setChangedNetwork(chainId); - } // from a React useState + setChangedNetwork(chainId); // from a React useState + } }; selectedWalletSWO.on('networkChanged', handleNetwork); ``` -### Unsubscribe +#### Unsubscribe Similar to subscription, by using the `.off` method. @@ -141,7 +184,44 @@ You can subscribe both with the SWO or with a `WalletAccount` instance. The above examples are using the SWO, because it is the simpler way to process. ::: -## Direct access to the wallet API entry points +## WalletAccount usage + +### Use as an Account + +Once a new `WalletAccount` or `WalletAccountV5` is created, you can use all the power of Starknet.js, exactly as a with a normal `Account` instance, for example `myWalletAccount.execute(call)` or `myWalletAccount.signMessage(typedMessage)`: + +```typescript +const claimCall = airdropContract.populate('claim_airdrop', { + amount: amount, + proof: proof, +}); +const resp = await myWalletAccount.execute(claimCall); +``` + +![](./pictures/executeTx.png) + +### Use in a Contract instance + +You can connect a `WalletAccount` with a [`Contract`](../API/classes/Contract) instance. All reading actions are performed by the provider of the `WalletAccount`, and all writing actions (that need a signature) are performed by the wallet. + +```typescript +const lendContract = new Contract(contract.abi, contractAddress, myWalletAccount); +const qty = await lendContract.get_available_asset(addr); // use of the WalletAccount provider +const resp = await lendContract.process_lend_asset(addr); // use of the wallet +``` + +### Use as a Provider + +Your `WalletAccount` instance can be used as a provider: + +```typescript +const bl = await myWalletAccount.getBlockNumber(); +// bl = 2374543 +``` + +You can use all the methods of the `RpcProvider` class. Under the hood, the `WalletAccount` will use the RPC node that you indicated at its instantiation. + +### Direct access to the wallet API entry points The `WalletAccount` class is able to interact with all the entrypoints of the Starknet Wallet API, including some functionalities that do not exists in the `Account` class. @@ -149,7 +229,7 @@ A full description of this API can be found [**here**](https://github.com/starkn Some examples: -### Request to change the wallet network +#### Request to change the wallet network Using your `WalletAccount`, you can ask the wallet to change its current network: @@ -169,7 +249,7 @@ useEffect( ![](./pictures/switchNetwork.png) -### Request to display a token in the wallet +#### Request to display a token in the wallet Using your `WalletAccount`, you can ask the wallet to display a new token: @@ -194,7 +274,7 @@ useEffect( ![](./pictures/addToken.png) -## Changing the network or account +### Changing the network or account When you change the network or the account address a `WalletAccount` instance is automatically updated, however, this can lead to unexpected behavior if one is not careful (reads and writes targeting different networks, problems with Cairo versions of the accounts, ...).