If you want to start creating assets that can be transferred amongst users, you can do it with codechain-sdk-js. If you visit this link, you can see an example JavaScript code. This page will guide you along on how to use codechain-sdk-js based on the example provided, called “Mint 10000 Gold and send 3000 Gold using AssetMintTransaction, AssetTransferTransaction”.
Before following any examples, please make sure to carefully go through the setup section before starting any examples.
Then, check whether your CodeChain RPC server is up and running. You can read about how that is done in the configure section.
Before you begin with various examples, you need to setup an account. The given account (cccqzn9jjm3j6qg69smd7cn0eup4w7z2yu9myd6c4d7) holds 100000 CCC at the genesis block. It's a sufficient amount to pay for the parcel fee. You can setup the account by using this:
wget https://raw.githubusercontent.com/CodeChain-io/codechain-sdk-js/master/examples/import-test-account.js
If successful, the command line will output the address of the account being used for the parcel fee. In this case, it will output cccqzn9jjm3j6qg69smd7cn0eup4w7z2yu9myd6c4d7.
Then run the downloaded .js file with the following command:
node import-test-account.js
Note
The initial 100000 CCC is only available in test mode.
Once you have installed codechain-sdk, go to the installed directory and create a JavaScript file with the example code. For simplicity, we will call this sample script mint-and-transfer.js. To download the .js file, run:
wget https://raw.githubusercontent.com/CodeChain-io/codechain-sdk-js/master/examples/mint-and-transfer.js
Then, run the following command:
node mint-and-transfer.js
This should give you the following result:
Asset { assetType: H256 { value: '5300000000000000179399be5182ae43b92acbb9de935000f5e33c23e6d4ceba' }, lockScriptHash: H256 { value: 'f42a65ea518ba236c08b261c34af0521fa3cd1aa505e1c18980919cb8945f8f3' }, parameters: [ [ 208, 251, 253, 21, 232, 131, 214, 80, 73, 177, 128, 232, 250, 151, 108, 210, 60, 69, 101, 113, 113, 130, 172, 17, 195, 42, 207, 229, 248, 152, 159, 14 ] ], amount: 3000, outPoint: AssetOutPoint { transactionHash: H256 { value: '5724c9377508058a27b7fbff10d60255a429ef905792986c07571fcaf0fff980' }, index: 0, assetType: H256 { value: '5300000000000000179399be5182ae43b92acbb9de935000f5e33c23e6d4ceba' }, amount: 3000, lockScriptHash: H256 { value: 'f42a65ea518ba236c08b261c34af0521fa3cd1aa505e1c18980919cb8945f8f3' }, parameters: [ [Array] ] } } Asset { assetType: H256 { value: '5300000000000000179399be5182ae43b92acbb9de935000f5e33c23e6d4ceba' }, lockScriptHash: H256 { value: 'f42a65ea518ba236c08b261c34af0521fa3cd1aa505e1c18980919cb8945f8f3' }, parameters: [ [ 174, 155, 53, 229, 89, 202, 36, 156, 33, 75, 16, 147, 201, 78, 224, 71, 48, 132, 174, 192, 113, 187, 89, 29, 225, 236, 112, 109, 204, 115, 84, 88 ] ], amount: 7000, outPoint: AssetOutPoint { transactionHash: H256 { value: '5724c9377508058a27b7fbff10d60255a429ef905792986c07571fcaf0fff980' }, index: 1, assetType: H256 { value: '5300000000000000179399be5182ae43b92acbb9de935000f5e33c23e6d4ceba' }, amount: 7000, lockScriptHash: H256 { value: 'f42a65ea518ba236c08b261c34af0521fa3cd1aa505e1c18980919cb8945f8f3' }, parameters: [ [Array] ] } }
In this example, 10000 gold has been minted for Alice. Alice then sends 3000 gold to Bob. Let’s see how all of this works specifically by inspecting parts of the code one by one.
Make sure you are accessing the CodeChain port. In this example, it is assumed that you are using port 8080, since that is the default value.
const sdk = new SDK({ server: “http://localhost:8080” });
The MemoryKeyStore is created for testing purposes. In real applications, the MemoryKeyStore would be in the form of storage, such as hardware wallets or the key store server, which would hold and manage the key pair (private and public keys). If you want to use the key store server see below remote key store. The P2PKH is responsible for locking and unlocking scripts.
const keyStore = await sdk.key.createMemoryKeyStore(); const p2pkh = await sdk.key.createP2PKH({ keyStore });
Each user needs an address to receive/send assets. Addresses are created by p2pkh. In this example, Bob's address is introduced differently, since Bob's address is recieved from Bob. In real world applications, you would only know the address of the recipient and nothing more.
const aliceAddress = await p2pkh.createAddress(); const bobAddress = "ccaqqqap7lazh5g84jsfxccp686jakdy0z9v4chrq4vz8pj4nl9lzvf7rs2rnmc0";
If you want to see Alice's address, run the following:
console.log(aliceAddress.toString());
This will result in showing you an address that is identical to the format of Bob's address shown above.
In order to create new assets, you must create a new instance of AssetScheme. In this example, we create 10000 gold with the following code:
const goldAssetScheme = sdk.core.createAssetScheme({ shardId: 0, metadata: JSON.stringify({ name: "Gold", description: "An asset example", icon_url: "https://gold.image/", }), amount: 10000, approver: null, });
Note
You should note that the approver is kept as null. This value is only filled out when there should be an overseer amongst transactions. If not null, the approver must approve of every transaction being made with that newly created Asset. In this case, if the 10000 gold that was minted had a approver, then every time any of those 10000 gold is involved in a transaction, the set approver would have to sign off and approve for the transaction to be successful.
After Gold has been defined in the scheme, the amount that is minted but belong to someone initially. In this example, we create 10000 gold for Alice.
const mintTx = sdk.core.createAssetMintTransaction({ scheme: goldAssetScheme, recipient: aliceAddress
Alice then sends 3000 gold to Bob. In CodeChain, users must follow the UTXO standard, and make a transaction that spends an entire UTXO balance, and receive the change back through another transaction.
Next, we create an output which gives 3000 gold to Bob, and returns 7000 gold to Alice.
const firstGold = mintTx.getMintedAsset(); const transferTx = sdk.core.createAssetTransferTransaction() .addInputs(firstGold) .addOutputs({ recipient: bobAddress, amount: 3000, assetType: firstGold.assetType }, { recipient: aliceAddress, amount: 7000, assetType: firstGold.assetType });
By using Alice's signature, the 10000 gold that was first minted can now be transferred to other users like Bob.
await transferTx.sign(0, { signer: p2pkh }); transferTx.getTransferredAssets();
The parcel containing the Gold asset is sent to the node. The parcel fee is paid for by the account known as
cccqzn9jjm3j6qg69smd7cn0eup4w7z2yu9myd6c4d7
with the passphrase satoshi
.
const parcel = sdk.core.createAssetTransactionParcel({ transaction: mintTx }); await sdk.rpc.chain.sendParcel(parcel, { account: "cccqzn9jjm3j6qg69smd7cn0eup4w7z2yu9myd6c4d7", passphrase: "satoshi", });
In order to check if all the transactions were successful, we run the following:
// Unspent Bob's 3000 golds console.log(await sdk.rpc.chain.getAsset(transferTx.hash(), 0)); // Unspent Alice's 7000 golds console.log(await sdk.rpc.chain.getAsset(transferTx.hash(), 1));
This should return the following:
[RESULTS WILL BE FIXED AND REUPLOADED]
[EXPLANATION WILL BE REVISED]
These are the values of each individual’s LockScripts that went through the blake256 hash function. If you run each individual’s LockScript under blake256 yourself, you will find that it corresponds to the rightful owners of the assets.
CodeChain adopted Bitcoin's Bech32 Specification. However,
there are differences. Codechain does not have a seperator. Also, there are two types of addresses used in CodeChain, which are
Platform Address and Asset Address. Platform Addresses are used for CCC, while Asset Addresses are used
for mintable assets. These addresses have a human readable part, followed by code. Platform Addresses have a "ccc"
tag, while
Asset Addresses have a "cca"
tag.
HRP: "ccc"
for Mainnet, "tcc"
for Testnet.
Data Part: version
. body
Version 0 (0x00)
Data body: Account ID
(20 bytes)
Account ID is a result of ripemd160 of blake256 of a public key (64 bytes uncompressed form).
HRP: "cca"
for Mainnet, "tca"
for Testnet.
Data: version
. body
Version 0 (0x00)
Data body: type
. payload
Type 0 (0x00) Payload: <LockScriptHash> (32 bytes)
Type 0 with given payload represents:
Lock Script Hash: <LockScriptHash> Parameters: [] Type 1 (0x01) Payload: <Public Key Hash> (32 bytes)
Type 1 with given payload represents:
Lock Script Hash: P2PKH Standard Script Hash Parameters: [<Public Key Hash>]
You should use a key management server to use Asset Address private keys safely. You can use a standalone key management server from this link. In this section, we will install and run the key management server, and use the server in the SDK.
To run the key management server, nodejs and yarn should be installed.
Clone CodeChain-Keystore repository from the below URL.
git clone https://github.com/CodeChain-io/codechain-keystore-server.git
Move to the directory
cd codechain-keystore
Install the dependencies
yarn install
Below command will run the server
NODE_ENV=production yarn run start
The SDK can use the key management server through RemoteKeyStore
class.
const keyStore = await sdk.key.createRemoteKeyStore("http://<key-management-server-address>");
If you are running the keystore server in the same machine, you can use the keyStore
object instead of the memory keystore. Refer to the example below:
const keyStore = await sdk.key.createRemoteKeyStore("http://127.0.0.1:7007");
Here is a sample which uses RemoteKeyStore
to create and get accounts. If you run this example multiple times, the number of printed keys is increased every time.
var { RemoteKeyStore } = require("codechain-sdk/lib/key/classes") async function main() { var keyStore = await RemoteKeyStore.create("http://<key-management-server-address>"); await keyStore.createKey({ passphrase: "mypassword" }); var keys = await keyStore.getKeyList(); console.dir(keys); } main().catch(err => console.error(err));