Deploy Token Wallet
In this section, we will explore an important aspect of deploying the TIP-3 standard contracts, which involves deploying a token wallet from a smart contract other than the token root contract. Specifically, we will focus on deploying a token wallet using the MultiWalletTIP3 contract.
Step 1: Write Deployment Script
We can utilize the code sample below to deploy a token wallet and retrieve its address from the multi wallet contract with help of the locklift tool and the stats of the previously written script from the deploy token root section .
INFO
Before we start to write our scripts we need to make sure that there is a file named 04-deploy-wallet.ts
in the script
folder in the project root.
In this section, we will cover the process of deploying a token wallet using the Multi Wallet TIP-3 contract. Please note that this operation can only be executed if the user does not possess an existing wallet for the respective token. Furthermore, to successfully deploy a token wallet for a token root using everscale-inpage-provider
, you will require the addresses of both the token root and the multi wallet.
INFO
According to the Multi Wallet contract, it stores the wallet information and its corresponding balance. This balance is dynamically updated whenever there are token minting, burning, or transfer operations involving the wallet.
/* Deploying Token Wallet contract using Multi Wallet TIP-3 */
// Deploying a TokenWallet contract using the using multi wallet contract for alice
// We will deploy another token wallet for bob at the time of transferring he tokens
await aliceMultiWalletContract.methods
.deployWallet({
_deployWalletBalance: locklift.utils.toNano('3'),
_tokenRoot: tokenRootContract.address,
})
.sendExternal({ publicKey: signerAlice.publicKey });
// Fetching the newly deployed Token Wallet
let tokenWalletData = await getWalletData(
aliceMultiWalletContract,
tokenRootContract.address
);
const aliceTokenWalletContract: Contract<
FactorySource['TokenWallet']
> = locklift.factory.getDeployedContract(
'TokenWallet',
tokenWalletData.tokenWallet
);
console.log(
'Alice Token wallet address: ',
tokenWalletData.tokenWallet.toString()
);
// Import the following libraries
import {
ProviderRpcClient,
Address,
FullContractState,
} from 'everscale-inpage-provider';
import * as tip3Artifacts from 'tip3-docs-artifacts';
import { provider, providerAddress } from './useProvider';
/**
* We develop two more methods in order to reduce the mass of the script
*/
// This function will extract the public key of the sender
async function extractPubkey(
provider: ProviderRpcClient,
senderAddress: Address
): Promise<string> {
// Fetching the user public key
const accountFullState: FullContractState = (
await provider.getFullContractState({ address: senderAddress })
).state!;
const senderPublicKey: string = await provider.extractPublicKey(
accountFullState.boc
);
return senderPublicKey;
}
async function main() {
try {
// Required contracts addresses
const tokenRootAddress: Address = new Address(
'<YOUR_TOKEN_ROOT_ADDRESS>'
);
const multiWalletAddress: Address = new Address(
'<YOUR_MULTI_WALLET_TIP3_ADDRESS>'
);
// Creating instances of the required contracts
const tokenRootContract = new provider.Contract(
tip3Artifacts.factorySource['TokenRoot'],
tokenRootAddress
);
const MultiWalletContract = new provider.Contract(
tip3Artifacts.factorySource['MultiWalletTIP3'],
multiWalletAddress
);
// Fetching the symbol
const symbol: string = (
await tokenRootContract.methods.symbol({ answerId: 0 }).call()
).value0;
// Checking if the user already doesn't have any wallet of that token root
let tokenWalletData = (
await MultiWalletContract.methods.wallets().call()
).wallets.map(item => {
if (
item[0].toString() == tokenRootContract.address.toString()
) {
return item[1];
}
});
if (
tokenWalletData[0]!.tokenWallet.toString() !=
tip3Artifacts.zeroAddress.toString()
) {
throw new Error(
'Failed, You already have a wallet of this token !'
);
}
// Deploying a new token wallet if it doesn't exists before
const { transaction: deployWalletRes } =
await MultiWalletContract.methods
.deployWallet({
_deployWalletBalance: 2 * 10 ** 9,
_tokenRoot: tokenRootContract.address,
})
.sendExternal({
publicKey: await extractPubkey(provider, providerAddress),
});
// Throwing an error if the transaction was aborted
if (deployWalletRes.aborted) {
throw new Error(
`Transaction aborted ! ${
(deployWalletRes.exitCode, deployWalletRes.resultCode)
}`
);
}
// Fetching the new wallet data from the multi wallet contract and check if its deployed successfully or not
tokenWalletData = (
await MultiWalletContract.methods.wallets().call()
).wallets.map(item => {
if (
item[0].toString() == tokenRootContract.address.toString()
) {
return item[1];
}
});
if (
tokenWalletData[0]!.tokenWallet.toString() !=
tip3Artifacts.zeroAddress.toString()
) {
console.log('Token Wallet successfully deployed !');
return `${symbol}'s token wallet deployed to: ${tokenWalletData[0]!.tokenWallet.toString()}`;
} else {
throw new Error(
`The token wallet deployment failed ! ${
(deployWalletRes.exitCode, deployWalletRes.resultCode)
}`
);
}
} catch (e: any) {
throw new Error(`Failed ${e.message}`);
}
}
Step 2: Deploy a TokenWallet
Use this command and deploy token wallet
npx locklift run -s ./scripts/04-deploy-wallet.ts -n local
Congratulations, you have deployed a TIP3 Token Wallet from the Multi Wallet TIP-3 contract 🎉
Token Root address
Multi Wallet TIP-3 address