Find out how to deploy a contract to Acki Nacki Blockchain with SDK
- About deploy
- Deploy steps
- Observe deploy parameters
- Prepare a pair of keys
- [Optional] Prepare initial contract data
- Specify constructor
- Calculate the future contract address
- Transfer funds to the future address
- Deploy
- Deploy a contract from another contract
- Sample Source Code
Core api is more flexible than AppKit, and you can perform a lot of complex logic using it. But you will need to write more code with it as well:)
You need to define the contract in your node.js application before deploy.
See the "Add Contract to your App" guide to find out how to do it.
Deploy operation means that you upload contract code and initial data to the blockchain.
The address of the contract can be calculated before deploy and it depends on code and data.
To deploy a contract you need to sponsor its address, so that deploy fee will be paid out of these funds.
Below is the sequence of steps you need to complete:
- Observe deploy parameters
- Prepare a pair of keys
- [optional] Prepare Initial contract data
- Calculate future address of the contract
- Transfer funds to the future address
- Deploy
Let's take a look at every step.
Here is the structure, that is used to prepare initial contract state for deploy. It will define the future contract address.
tvc
- As we discussed at the previous step, contract compilation artifact, converted into base64.
workchain_is
- Target workchain where the contract will be deployed. By default is 0.
initial_data
- structure that contains public contract data fields with assigned values that need to be included into the initial state.
initial_pubkey
- owner pubkey. If not specified, pubkey is taken from Signer
. If you manage to specify contract owner directly in tvc
, then it will have priority above both initial_pubkey
and Signer
.
type DeploySet = {
tvc: string,
workchain_id?: number,
initial_data?: any,
initial_pubkey?: string
}
To deploy you will need a pair of keys to sign the deployment message. The keys are used during address generation, so the future contract address depends partially on the key as well.
In fact, keys are optional for deploy, but, if you want to be the contract owner then specify Signer object for that. Read more about Signer object in Reference.
If you want to make another person owner of the contract then specify their pubkey via DeploySet.initial_pubkey
.
In this guide we will use crypto.generate_random_sign_keys
function to generate a key pair.
const helloKeys = await client.crypto.generate_random_sign_keys();
Note: Please store these keys in a secure environment as you will need them to calculate the future address and deploy the contract. You might also need it to call contract functions in the future.
Placing data into storage always affects the future contract address.
This is useful for scenarios when you need to deploy several contracts with identical contract code (e.g. wallets) to different addresses.
If each contract is deployed with its own unique pair of keys, you do not need to use DeploySet.initial_data
as the addresses will be generated using the corresponding key pair each time.
If, however, all the contracts need to have the same contract code and have to be deployed with the same pair of keys but to different addresses, you may use placing data into storage through DeploySet.initial_data
to vary the addresses during address calculation.
To be used as initParams
variables must be declared as static
in the contract.
Constructor - is any contract function that will be called upon deploy. It will not influence contract address.
It, together with its parameters, is specified in the CallSet structure:
type CallSet = {
function_name: string,
header?: FunctionHeader,
input?: any
}
function_name
- function name that will be called upon deploy. Usually, it is called constructor
.
header
- optional, can be specified for some complex use cases. Read more here.
input
- object with function parameters.
Acki Nacki blockchain requires every contract to have a positive token balance before deployment. The contract pays for the initial deployment message reducing account balance.
We will create deploy message and get future contract address from it.
You can either specify or not specify call_set here, it will not influence the address.
const abi = {
type: 'Contract',
value: contract.abi
}
// Generate an ed25519 key pair
const helloKeys = await client.crypto.generate_random_sign_keys();
// Prepare parameters for deploy message encoding
// See more info about `encode_message` method parameters here https://github.com/tonlabs/ever-sdk/blob/master/docs/mod_abi.md#encode_message
const deployOptions = {
abi,
deploy_set: {
tvc: contractPackage.tvcInBase64,
initial_data: {}
},
// can be ommited here for address calculation
call_set: {
function_name: 'constructor',
input: {}
},
signer: {
type: 'Keys',
keys: helloKeys
}
}
// Encode deploy message
// Get future `Hello` contract address from `encode_message` result
// to sponsor it with tokens before deploy
const { address } = await client.abi.encode_message(deployOptions);
console.log(`Future address of the contract will be: ${address}`);
Note: Deployment requires the same pair of keys used for address calculation.
Note:
constructorParams
do not affect the address. OnlyinitParams
and the keys do. If you only plan to calculate address, you can omit this parameter.
Now that you know the address, you need to transfer the initial funds to it from your wallet or the Giver.
Note: Evernode SE offers a pre-deployed giver. When in real networks, you need to use your wallet for this or deploy your own giver. We have separated guides of deployment and usage of your own giver.
// Request contract deployment funds form a local Evernode SE giver
// not suitable for other networks
await get_tokens_from_giver(client, address);
console.log(`Tokens were transfered from giver to ${address}`);
At this point, you're all set for deployment.
Note: Insufficient balance will result in a failed deployment.
Note: Acki Nacki Blockchain does not guarantee a 100% external inbound messages success rate. There is a possibility that deployment will fail. To ensure success, please check for a completed transaction.
This is an easy to implement pattern to deploy for server-side development and tests, but we do not recommend to use it in web and mobile applications because of network inconsistency and application crash probability. For more reliable approach - use the Pattern 2.
Method `process_message performs all the deploy steps sequentially in one method: create message, send it, wait for transaction and decode external outbound message generated by contract RETURN operator. The time limit can be set up in Client configuration. The default time setting is 40 seconds. You can learn more here.
// Deploy `hello` contract
// See more info about `process_message` here
// https://github.com/tonlabs/ever-sdk/blob/master/docs/mod_processing.md#process_message
await client.processing.process_message({
send_events: false,
message_encode_params: deployOptions
});
console.log(`Hello contract was deployed at address: ${address}`);
See the full example in sdk samples repository:
https://github.com/tonlabs/sdk-samples/blob/master/core-examples/node-js/hello-wallet/index.js
Check out how to run contract's methods in the next section.
Any interaction with and within the Acki Nacki blockchain is implemented via messages.
To deploy a contract, first you need to create a deploy message that will include all the initial data:
// Prepare parameters for deploy message encoding
// See more info about `encode_message` method parameters here https://github.com/tonlabs/ever-sdk/blob/master/docs/mod_abi.md#encode_message
const deployOptions = {
abi: {
type: 'Contract',
value: contract.abi
},
deploy_set: {
tvc: contractPackage.tvcInBase64,
initial_data: {}
},
call_set: {
function_name: 'constructor',
input: {}
},
signer: {
type: 'Keys',
keys: helloKeys
}
}
// Encode deploy message
// Get future `Hello` contract address from `encode_message` result
// to sponsor it with tokens before deploy
const encode_deploy_result = await client.abi.encode_message(deployOptions);
Now the message should be sent. send_message
method returns the the last block created in the shard before the message was sent.
send_events: false
flag specifies that we will not monitor message delivery events. Soon there will be a guide about message processing monitoring.
// Send deploy message to the network
// See more info about `send_message` here
// https://github.com/tonlabs/ever-sdk/blob/master/docs/mod_processing.md#send_message
var shard_block_id;
shard_block_id = (await client.processing.send_message({
message: encode_deploy_result.message,
send_events: false
},
)).shard_block_id;
console.log(`Deploy message was sent.`);
After the message was sent we need to wait for the transaction:
// Monitor message delivery.
// See more info about `wait_for_transaction` here
// https://github.com/tonlabs/ever-sdk/blob/master/docs/mod_processing.md#wait_for_transaction
const deploy_processing_result = await client.processing.wait_for_transaction({
abi: {
type: 'Contract',
value: contract.abi
},
message: encode_deploy_result.message,
shard_block_id: shard_block_id,
send_events:false // we do not want to monitor processing events
}
)
console.log(`Deploy transaction: ${JSON.stringify(deploy_processing_result.transaction,null,2)}`);
console.log(`Deploy fees: ${JSON.stringify(deploy_processing_result.fees,null,2)}`);
console.log(`Hello contract was deployed at address: ${address}`);
If wait_for_transaction
fails with 507 error - you can perform a retry. In all other cases retry may end up with double spends.
See the full example in sdk samples repository:
Check out how to run contract's methods in the next section.
Often developers need to deploy one contract from another contract and try to pass tvc
file as a cell parameter for contract to use.
This is not a correct way.
To be able to deploy a contract from another contract you need to pass the contract's code as a cell parameter.
You can get it several ways:
- You can use SDK function get_code_from_tvc of
boc
module and retrieve the code's boc from tvc file. - You can download another account with the same
code_hash
'sboc
from graphql, using blockchain API and retrieve the 'code' from the resultboc
field.
Full sample: https://github.com/tonlabs/sdk-samples/blob/master/core-examples/node-js/hello-wallet/
Check out AppKit documentation for this use case.