Deploy Token Root
In this section, we will learn a little more about the memory structure and StateInit in the TVM (Ton Virtual Machine), and deploy our token root contract through a smart contract.
Memory Structure and State Init
TVM memory and persistent storage consist of cells. Remember that the TVM memory and persistent storage consist of (TVM) cells.
tvm.buildStateInit
- Generates a StateInit
from code
and data
TvmCell
s. Member splitDepth
of the tree of cell StateInit
:
- is not set. Has no value.
- is set.
0 <= splitDepth <= 31
- Arguments can also be set with names. List of possible names:
code
(TvmCell
) - defines the code field of theStateInit
. Must be specified.data
(TvmCell
) - defines the data field of theStateInit
. Conflicts withpubkey
andvarInit
. Can be omitted, in this case data field would be build frompubkey
andvarInit
.splitDepth
(uint8
) - splitting depth.0 <= splitDepth <= 31
. Can be omitted. By default, it has no value.pubkey
(uint256
) - defines the public key of the new contract. Conflicts withdata
. Can be omitted, default value is 0.varInit
(initializer list
) - used to set static variables of the contract. Conflicts withdata
and requirescontr
to be set. Can be omitted.contr
(contract
) - defines the contract whoseStateInit
is being built. Mandatory to be set if the optionvarInit
is specified.
Step 1: Write Deployment Script
Follow the instructions below to deploy a TokenRoot
using the rootDeployer
contract with the locklift tool and the state of the previously written script for deploying the RootDeployer.
INFO
Before we start to write our scripts we need to make sure that there is a file named 03-deploy-token.ts
in the script
folder in the project root.
Deploying a token root using everscale-inpage-provider is now made easier with the Multi Wallet contract, as demonstrated in the code samples below:
WARNING
The parameter initialSupply
must be set to zero if the initialSupplyTo
is zero address.
/* Deploying Token Root contract using root Deployer */
// Defining an interface for tokens root deployment using the root deployer contract
interface deployRootParams {
initialSupplyTo: Address;
rootOwner: Address;
name: string;
symbol: string;
decimals: number;
mintDisabled: boolean;
burnByRootDisabled: boolean;
burnPaused: boolean;
initialSupply: number;
deployWalletValue: number;
randomNonce: number;
remainingGasTo: Address;
}
// Preparing the deployment params
const deployRootFromDeployerParams: deployRootParams = {
name: 'Tip3OnboardingToken',
decimals: 6,
initialSupplyTo: zeroAddress,
initialSupply: 0,
deployWalletValue: 0,
symbol: 'TOT',
mintDisabled: false,
rootOwner: aliceAccount.address,
randomNonce: locklift.utils.getRandomNonce(),
burnByRootDisabled: false,
burnPaused: false,
remainingGasTo: aliceAccount.address,
};
// Deploying the token root utilizing an external message to the root deployer contract
await rootDeployer.methods
.deployTokenRoot(deployRootFromDeployerParams)
.sendExternal({
publicKey: signerAlice.publicKey,
});
// Confirming tha that the token root is deployed by calling its name method
const tokenRootContract: Contract<FactorySource['TokenRoot']> =
locklift.factory.getDeployedContract(
'TokenRoot',
(
await rootDeployer.methods
.getExpectedTokenRootAddress({
name: deployRootFromDeployerParams.name,
decimals: deployRootFromDeployerParams.decimals,
symbol: deployRootFromDeployerParams.symbol,
rootOwner: deployRootFromDeployerParams.rootOwner,
randomNonce: deployRootFromDeployerParams.randomNonce,
})
.call()
).value0
);
console.log(
`Token Root address : ${tokenRootContract.address.toString()} \n Token Root name: ${
(await tokenRootContract.methods.name({ answerId: 0 }).call())
.value0
}`
); // >> Tip3OnboardingToken
import {
ProviderRpcClient,
Address,
GetExpectedAddressParams,
Contract,
Transaction,
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() {
// Initiate the TVM provider
// Token Root contracts abi
const tokenRootAbi: tip3Artifacts.FactorySource['TokenRoot'] =
tip3Artifacts.factorySource['TokenRoot'];
// Creating an instance of the root deployer contract
const rootDeployerAddress: Address = new Address(
'<YOUR_ROOT_DEPLOYER_ADDRESS>'
);
const rootDeployerAbi: tip3Artifacts.FactorySource['RootDeployer'] =
tip3Artifacts.factorySource['RootDeployer'];
const rootDeployerContract: Contract<
tip3Artifacts.FactorySource['RootDeployer']
> = new provider.Contract(rootDeployerAbi, rootDeployerAddress);
// Defining an interface for tokens root deployment using the root deployer contract
interface deployRootParams {
initialSupplyTo: Address;
rootOwner: Address;
name: string;
symbol: string;
decimals: number;
mintDisabled: boolean;
burnByRootDisabled: boolean;
burnPaused: boolean;
initialSupply: number;
deployWalletValue: number;
randomNonce: number;
remainingGasTo: Address;
}
// Preparing the parameters
const params: deployRootParams = {
initialSupplyTo: tip3Artifacts.zeroAddress,
rootOwner: providerAddress,
randomNonce: (Math.random() * 6400) | 0,
deployWalletValue: 0,
name: 'Tip3OnboardingToken',
symbol: 'TOT',
decimals: 6,
mintDisabled: false,
burnByRootDisabled: false,
burnPaused: false,
initialSupply: 0,
remainingGasTo: providerAddress,
};
// Deploying the tokenRoot
const { transaction: deployRes } =
await rootDeployerContract.methods
.deployTokenRoot(params)
.sendExternal({
publicKey: await extractPubkey(provider, providerAddress),
});
// Throwing an error if the transaction was aborted
if (deployRes.aborted) {
throw new Error(
`transaction aborted ${
(deployRes.exitCode, deployRes.resultCode)
}`
);
}
// Fetching the address of the token root
const tokenRootAddr: Address = (
await rootDeployerContract.methods
.getExpectedTokenRootAddress({
name: params.name,
decimals: params.decimals,
symbol: params.symbol,
rootOwner: params.rootOwner,
randomNonce: params.randomNonce,
})
.call()
).value0;
// making an instance of the token root
const tokenRootContract: Contract<
tip3Artifacts.FactorySource['TokenRoot']
> = new provider.Contract(tokenRootAbi, tokenRootAddr);
// checking if the token root is deployed successfully by calling one of its methods
const tokenName: string = (
await tokenRootContract.methods.name({ answerId: 0 }).call({})
).value0;
if (tokenName == params.name) {
console.log(`${params.symbol} Token deployed successfully`);
return `${params.symbol} deployed to ${tokenRootAddr.toString()}`;
} else {
throw new Error(
`${params.symbol} Token deployment failed !${deployRes.exitCode}`
);
}
}
Step 2: Deploy Token Root
Let's run our script using locklift
npx locklift run -s ./scripts/03-deploy-token.ts -n local
Congratulations, you have deployed a TIP3 Token Root through the Root Deployer contract 🎉
Root deployer
initialSupplyTo
rootOwner
name
symbol
decimals
initialSupply