Deploy a Tokenized Asset
This guide covers how to publish the asset tokenization packages and interact with your tokenized asset.
- Prerequisites
- Install Sui
- Configure a Sui client
- Get SUI from faucet
- Node.js and npm installed
- Git installed
Clone the repository​
Clone the asset-tokenization repository and navigate to the setup directory:
$ git clone https://github.com/MystenLabs/asset-tokenization.git
$ cd asset-tokenization
Copy the .env.template file to .env and install dependencies:
$ cp setup/.env.template setup/.env
$ cd setup && npm install
Initialize the Sui Client CLI​
See "Hello, World!" for a more detailed guide on publishing packages or Sui Client CLI for a complete reference of client commands in the Sui CLI.
Before publishing your code, you must first initialize the Sui Client CLI, if you haven't already. To do so, in a terminal or console at the root directory of the project enter sui client. If you receive the following response, complete the remaining instructions:
Config file ["<FILE-PATH>/.sui/sui_config/client.yaml"] doesn't exist, do you want to connect to a Sui full node server [y/N]?
Enter y to proceed. You receive the following response:
Sui full node server URL (Defaults to Sui Testnet if not specified) :
Leave this blank (press Enter). You receive the following response:
Select key scheme to generate key pair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):
Select 0. Now you should have a Sui address set up.
Publishing​
You can publish the contracts manually using the Sui CLI, or use the provided bash script to automatically deploy and populate most of the .env fields.
The setup/.env.template file defines all required variables. For more details, see the setup folder's README.
Publishing packages​
Publish both packages in order: asset_tokenization first, then template.
Beginning with the Sui v1.24.1 release, the --gas-budget option is no longer required for CLI commands.
asset_tokenization package​
You can publish the asset_tokenization package manually with sui client publish or automatically using the provided bash script (npm run publish-asset-tokenization), which also populates SUI_NETWORK, ASSET_TOKENIZATION_PACKAGE_ID, and REGISTRY in your .env file.
To publish manually, run the following from the move/asset_tokenization directory:
$ sui client publish --gas-budget <GAS-BUDGET>
The package should successfully deploy, and you then see:
UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING asset_tokenization
Successfully verified dependencies on-chain against source.
Store the package ID and registry ID from the created objects in your .env file. Then modify Move.toml: under the [addresses] section, replace 0x0 with the same package ID. Optionally, under the [package] section, add published-at = <package ID> (this step is not needed if you see a Move.lock file after running sui client publish).
For more details, see the setup folder's README.
template package​
You can publish the template package manually with sui client publish or automatically through the WASM library using npm run publish-template. Before running the automatic flow, ensure the asset_tokenization package address is set in the [addresses] section of asset_tokenization/Move.toml and matches the original deployment. If no Move.lock file exists, also populate the published-at field with the latest package deployment address.
To publish manually, run the following from the move/template directory:
$ sui client publish --gas-budget <GAS-BUDGET>
The package should successfully deploy, and you then see:
UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git
INCLUDING DEPENDENCY asset_tokenization
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING template
Successfully verified dependencies on-chain against source.
Store the package ID, asset metadata ID, asset cap ID, and Publisher ID from the created objects in your .env file.
For more details, see the setup folder's README.
WebAssembly (WASM) and the template package​
You can find a public-facing reference to the WASM library in the move-binary-format-wasm Sui repo subfolder.
The WASM feature enables Move bytecode serialization and deserialization in a browser environment, allowing you to edit existing contracts without a local build environment. For asset tokenization, this lets you create and publish new asset types directly from the browser.
Bytecode manipulation​
If you modify the template package, you must repeat this process. Some alterations, like changing a constant name, do not affect the produced bytecode.
The WASM library manipulates the compiled bytecode of the template module. To retrieve it, navigate inside the template folder and run:
$ xxd -c 0 -p build/template/bytecode_modules/template.mv | head -n 1
Console response
The response looks similar to the following:
a11ceb0b060000000a010010021026033637046d0a05776807df01ec0108cb03800106cb043
e0a8905050c8e0549001303140107010d01120215021602170004020001000c01000101010c
010001020307000302070100000403070006050200070607000009000100010a0a0b0102021
2050700030c010401000311060401000418050800050e0601010c050f1001010c06100d0e00
070b050300030304030109060c070f02080007080600040b040108070b010108000b0201080
00b04010807010807010b04010900010a020109000108030108050108000809000308030805
08050b0401080701070806020b010109000b02010900010b02010800010608060105010b010
10800020900050841737365744361700d41737365744d65746164617461064f7074696f6e06
537472696e670854454d504c415445095478436f6e746578740355726c0561736369690b647
56d6d795f6669656c6404696e6974096e65775f6173736574156e65775f756e736166655f66
726f6d5f6279746573046e6f6e65066f7074696f6e137075626c69635f73686172655f6f626
a6563740f7075626c69635f7472616e736665720673656e64657204736f6d6506737472696e
670874656d706c6174650f746f6b656e697a65645f6173736574087472616e736665720a747
85f636f6e746578740375726c04757466380000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000100000000000000000000000000000000000000000000000000000000000000
02d9ebdef1e3cb5eb135362572b18faeb61259afe651a463f1384745ebd7fd51da030864000
000000000000a02070653796d626f6c0a0205044e616d650a020c0b4465736372697074696f
6e0a02090869636f6e5f75726c0101010a02010000020108010000000002230704070621040
738000c02050b0704110938010c020b020c050b0007000701110207021105070311050b0507
050a0138020c040c030b0438030b030b012e110838040200
Copy the output and paste it into the return statement of the getBytecode method in bytecode-template.ts.
Because the template package contains 2 modules, you also need to retrieve the bytecode for the genesis module. This bytecode is not edited but is required to deploy the template module. Navigate to the template folder and run:
$ xxd -c 0 -p build/template/bytecode_modules/genesis.mv | head -n 1
Copy the output and paste it into the bytecode constant in genesis_bytecode.ts.
With this setup, the library can deserialize the bytecode, apply your edits, and serialize it again for publishing.
Template module constants​
The template module defines a set of constants that the WASM library can modify:
...
const TOTAL_SUPPLY: u64 = 100;
const SYMBOL: vector<u8> = b"Symbol";
const NAME: vector<u8> = b"Name";
const DESCRIPTION: vector<u8> = b"Description";
const ICON_URL: vector<u8> = b"icon_url";
const BURNABLE: bool = true;
...
The TypeScript code that performs the edit and deploys identifies and updates these constants:
...
const template = getBytecode();
const compiledModule = new CompiledModule(
JSON.parse(wasm.deserialize(template))
)
.updateConstant(0, totalSupply, "100", "u64")
.updateConstant(1, symbol, "Symbol", "string")
.updateConstant(2, asset_name, "Name", "string")
.updateConstant(3, description, "Description", "string")
.updateConstant(4, iconUrl, "icon_url", "string")
.updateConstant(5, burnable, "true", "bool")
.changeIdentifiers({
template: moduleName,
TEMPLATE: moduleName.toUpperCase(),
});
const bytesToPublish = wasm.serialize(JSON.stringify(compiledModule));
...
The updateConstant method takes 4 arguments:
idx: The index of the constant in the constant pool, sequential starting from 0.value: The updated value for the constant.expectedValue: The current value of the constant, used to reduce the risk of accidentally updating the wrong constant.expectedType: The current type of the constant, for the same reason.
The changeIdentifiers method updates identifiers such as the module name and struct name. It takes a JSON object with keys of the current identifier names and values of the desired names.
To deploy the changed template module, build and publish:
...
const tx = new Transaction();
tx.setGasBudget(100000000);
const [upgradeCap] = tx.publish({
modules: [[...fromHex(bytesToPublish)], [...fromHex(genesis_bytecode)]],
dependencies: [
normalizeSuiObjectId("0x1"),
normalizeSuiObjectId("0x2"),
normalizeSuiObjectId(packageId),
],
});
tx.transferObjects(
[upgradeCap],
tx.pure(signer.getPublicKey().toSuiAddress(), "address")
);
...
The modules array contains 2 elements: the edited template module and the genesis module. The packageId is the address the asset_tokenization package was deployed to.
TypeScript commands​
After publishing, use the TypeScript setup scripts to interact with your tokenized asset. For a full reference of available commands, see the Asset Tokenization TypeScript CLI Reference.