Transfer TIP-3 Tokens
We have already learned how to send messages to a contract through an account.
Therefore, making a transfer is as easy as shelling pears!
TIP
TIP-3 Token Wallet has 2 transfer methods:
- Transfer - Transfer tokens and optionally deploy TokenWallet for recipient account address.
- Transfer tokens using another TokenWallet address, that wallet must be deployed previously.
In the code sample provided below, we assume that Alice does not have a token wallet. Therefore, we begin by deploying a token wallet for Alice which will be accomplished when using the transfer
function. Subsequently, we can employ the transferToWallet
function to transfer a certain amount of TIP3 tokens to Alice.
Step 1: Write Transfer Script
In the code sample below, we will demonstrate how to transfer TIP-3 tokens using locklift:
Notice that we utilize the stats of the previously written script in the mint tip-3 section.
INFO
Before we start to write our scripts we need to make sure that there is a file named 04-transfer-tip3.ts
in the script
folder in the project root.
Transferring TIP-3 tokens is considered one of the easier steps depended to previous steps. let's look at the code samples below to see how its done using everscale-inpage-provider:
WARNING
- Notice that if the
notify
parameter be true for the transaction, the change will be sent back to the sender accountstokenWallet
contract !!
So if you want the change back into youraccount contract
leave the Notifyunchecked
!!
/* Transferring tip-3 tokens using transfer function */
console.log(
"Bob's balance before transfer: ",
Number(
(
await bobTokenWallet.methods
.balance({
answerId: 0,
})
.call()
).value0
) /
10 ** decimals
);
console.log('Alice balance before transfer: 0');
// Amount to transfer
const transferAmount: number = 30 * 10 ** decimals;
/*
Transfer with the deployment of a wallet for the recipient account.
Don't pay attention to notify and payload yet, we'll get back to them.
*/
await bobTokenWallet.methods
.transfer({
amount: transferAmount,
recipient: aliceAccount.address,
deployWalletValue: locklift.utils.toNano(2), // assume alice doesn't have any token wallet
remainingGasTo: bobAccount.address,
notify: false,
payload: '',
})
.send({
from: bobAccount.address,
amount: locklift.utils.toNano('5'),
});
/*
Creating the alice's token wallet and Checking Alice's balance
*/
const aliceTokenWallet: Contract<FactorySource['TokenWallet']> =
locklift.factory.getDeployedContract(
'TokenWallet',
(
await tokenRootContract.methods
.walletOf({
answerId: 0,
walletOwner: aliceAccount.address,
})
.call()
).value0
);
console.log(
"Bob's balance after transfer: ",
Number(
(
await bobTokenWallet.methods
.balance({
answerId: 0,
})
.call()
).value0
) /
10 ** decimals
);
console.log(
"Alice's balance after transfer: ",
Number(
(
await aliceTokenWallet.methods
.balance({
answerId: 0,
})
.call()
).value0
) /
10 ** decimals
);
/* Transferring tip-3 tokens using transferToWallet function */
await bobTokenWallet.methods
.transferToWallet({
amount: transferAmount,
recipientTokenWallet: aliceTokenWallet.address,
remainingGasTo: bobAccount.address,
notify: false,
payload: '',
})
.send({
from: bobAccount.address,
amount: locklift.utils.toNano('3'),
});
console.log(
"Bob's balance after transfer to wallet: ",
Number(
(
await bobTokenWallet.methods
.balance({
answerId: 0,
})
.call()
).value0
) /
10 ** decimals
);
console.log(
"Alice's balance after transfer to wallet: ",
Number(
(
await aliceTokenWallet.methods
.balance({
answerId: 0,
})
.call()
).value0
) /
10 ** decimals
);
// Import the required libraries
import {
ProviderRpcClient as PRC,
Address,
Contract,
Transaction,
} from 'everscale-inpage-provider';
import * as tip3Artifacts from 'tip3-docs-artifacts';
import { provider, providerAddress } from './useProvider';
async function main() {
// Preparing the required addresses
const tokenRootAddress: Address = new Address(
'<YOUR_TOKEN_ROOT_ADDRESS>'
);
const recipientAddress: Address = new Address(
'<RECIPIENT_ACCOUNT_ADDRESS>'
);
// creating an instance of the target token root contract
const tokenRootContract: Contract<
tip3Artifacts.FactorySource['TokenRoot']
> = new provider.Contract(
tip3Artifacts.factorySource['TokenRoot'],
tokenRootAddress
);
// getting the decimals of the token
const decimals = Number(
(await tokenRootContract.methods.decimals({ answerId: 0 }).call())
.value0
);
// creating an instance of the sender token wallet contract
const tokenWallet: Contract<
tip3Artifacts.FactorySource['TokenWallet']
> = new provider.Contract(
tip3Artifacts.factorySource['TokenWallet'],
(
await tokenRootContract.methods
.walletOf({ answerId: 0, walletOwner: providerAddress })
.call()
).value0
);
/**
* we will make an instance of the recipient token wallet contract and we assign value to it if the token wallet was already deployed
* the amount attached to the tx varies based on the mentioned subject.
*/
let recipientTokenWallet:
| Contract<tip3Artifacts.FactorySource['TokenWallet']>
| undefined = undefined;
const receiverTokenWalletAddress = (
await tokenRootContract.methods
.walletOf({ answerId: 0, walletOwner: recipientAddress })
.call()
).value0;
// Defining the transfer parameters
let txFee: number = 3 * 10 ** 9;
let oldBal: number = 0;
let deployWalletValue: number = 0;
// Setting the deployWalletValue and transaction fee based on the recipient token wallet deployment status
if (
!(
await provider.getFullContractState({
address: receiverTokenWalletAddress,
})
).state?.isDeployed
) {
txFee = 5 * 10 ** 9;
deployWalletValue = 2 * 10 ** 9;
} else {
recipientTokenWallet = new provider.Contract(
// Transferring the token
tip3Artifacts.factorySource['TokenWallet'],
receiverTokenWalletAddress
);
oldBal = Number(
(
await recipientTokenWallet.methods
.balance({ answerId: 0 })
.call({})
).value0
);
}
// Defining the transfer amount
let transferAmount: number = 10 ** (10 ** decimals);
// Transferring token
const transferRes: Transaction = await tokenWallet.methods
.transfer({
amount: transferAmount,
recipient: recipientAddress,
deployWalletValue: deployWalletValue,
remainingGasTo: providerAddress,
notify: false, // true if the change must be sent back to the sender wallet account not the sender token wallet
payload: '',
})
.send({
from: providerAddress,
amount: String(txFee),
bounce: true,
});
// Checking of the transaction is aborted or not
if (transferRes.aborted) {
throw new Error(
`Transaction aborted !: ${
(transferRes.exitCode, transferRes.resultCode)
}`
);
}
// In this case the recipient didn't have any token wallet and one is deployed during the transfer, so we fetch it since we haven't before
recipientTokenWallet = new provider.Contract(
// Transferring the token
tip3Artifacts.factorySource['TokenWallet'],
receiverTokenWalletAddress
);
// recipient balance after transfer
const newBal: number = Number(
(
await recipientTokenWallet.methods
.balance({ answerId: 0 })
.call({})
).value0
);
// Checking if the tokens are received successfully
if (newBal >= Number(transferAmount) * 10 ** decimals + oldBal) {
console.log('tokens transferred successfully');
} else {
throw new Error(
` Transferring tokens failed \n tx Hash: ${
(transferRes.exitCode, transferRes.resultCode)
}`
);
}
// transferring token to wallet
const transferToWalletRes: Transaction = await tokenWallet.methods
.transferToWallet({
amount: transferAmount * 10 ** decimals,
recipientTokenWallet: recipientTokenWallet.address,
remainingGasTo: providerAddress,
notify: false,
payload: '',
})
.send({
from: providerAddress,
amount: String(3 * 10 ** 9),
bounce: true,
});
// Throwing an error if the transaction was aborted
if (transferToWalletRes.aborted) {
throw new Error(`Transaction aborted !: ${transferRes.exitCode}`);
}
// newBal is actually the old balance and its fetched before utilizing the "transferToWallet" the function
if (
Number(
(
await recipientTokenWallet.methods
.balance({ answerId: 0 })
.call({})
).value0
) > newBal
) {
console.log('tokens transferred successfully');
return `tx Hash: ${transferRes.id.hash}`;
} else {
throw new Error(
`Transferring tokens failed, tx Hash: ${transferRes.id.hash}`
);
}
}
Step 2: Transfer TIP-3 Tokens
Use this command to transfer TIP-3 tokens:
npx locklift run -s ./scripts/04-transfer-tip3.ts -n local
Congratulations, you have successfully transferred TIP-3 tokens from one to another Wallet 🎉