EOSIO <> EOSIO Atomic Assets Non-Fungible Tokens
This guide will essentially map the atomictokenpegeosio.spec.js unit test.
Resources:
Steps:
  • ​Install Zeus if not installed, zeus is used to unbox or install all the necessary dependencies to compile and deploy the necessary contracts.
Ensure you're using node version 12, IPFS can be picky with other versions
  • ​Unbox atomictokenpeg box
1
mkdir atomictokenpeg; cd atomictokenpeg
2
zeus box create
3
zeus unbox atomictokenpeg
Copied!
  • Add LiquidX mapping file
/zeus_boxes/liquidx/models/eosio-chains/liquidxxtwax.json
The following file is for the destination chain's information.
1
# remove existing JSON file to not confuse the compiler
2
rm -rf ./zeus_boxes/liquidx/models/eosio-chains/
3
mkdir ./zeus_boxes/liquidx/models/eosio-chains/
4
touch ./zeus_boxes/liquidx/models/eosio-chains/liquidxxtwax.json
5
vim ./zeus_boxes/liquidx/models/eosio-chains/liquidxxtwax.json
Copied!
1
{
2
"dsp_port": 3117,
3
"webhook_dapp_port": 8813,
4
"nodeos_host": "testnet.waxsweden.org",
5
"nodeos_port": 443,
6
"secured": true,
7
"nodeos_state_history_port": 8887,
8
"nodeos_p2p_port": 12451,
9
"nodeos_endpoint": "https://testnet.waxsweden.org",
10
"demux_port": 1232,
11
"name": "liquidxxtwax",
12
"local": false
13
}
Copied!
/zeus_boxes/liquidx/models/liquidx-mappings/sidechain_name.dappservices.json
This file allows for the compiler to insert relevant chain information into the contract header.
1
# remove existing JSON
2
rm -rf ./zeus_boxes/liquidx/models/liquidx-mappings/
3
mkdir ./zeus_boxes/liquidx/models/liquidx-mappings/
4
touch ./zeus_boxes/liquidx/models/liquidx-mappings/liquidxxtwax.dappservices.json
5
vim ./zeus_boxes/liquidx/models/liquidx-mappings/liquidxxtwax.dappservices.json
Copied!
1
{
2
"sidechain_name": "liquidxxtwax",
3
"mainnet_account": "dappservices",
4
"chain_account": "dappservicex"
5
}
Copied!
  • Compile contracts
Update the atomic assets contract account name for each contract
1
// atomictokenpegeosio.cpp
2
const name NFT_ACCOUNT = "bridgeassets"_n;
3
// atomictokenpegxeosio.cpp
4
const name NFT_ACCOUNT = "atomicassets"_n;
Copied!
If you do not perform the above step before compiling, your bridge will not function because it will not be able to detect incoming transfers.
1
zeus compile atomictokenpegeosio; zeus compile atomictokenpegxeosio
Copied!
Examine ./contracts/eos/dappservices/dappservices.config.hpp and you will see the mapping field populate into c++ definitions, if you see TEST1, you need to delete the existing mapping files
  • Create 2 Kylin and 2 Wax Testnet Accounts
    • Kylin bridge contract Account (atomictokenpegeosio.cpp)
    • Kylin test Account no contract
    • Wax Testnet contract Account (atomictokenpegxeosio.cpp)
    • Wax Testnet Account no contract
We'll be using the existing atomicassets contracts on Kylin / Wax Testnet, so no need to create them.
1
export KYLIN_BRIDGE_ACCOUNT=atomicbridg1
2
export KYLIN_TOKEN_ACCOUNT=bridgeassets
3
export KYLIN_TEST_ACCOUNT=natdeveloper
4
export KYLIN_ENDPOINT=https://kylin.eosn.io
5
export WAX_TEST_BRIDGE_ACCOUNT=atomicbridg1
6
export WAX_TEST_TOKEN_ACCOUNT=atomicassets
7
export WAX_TEST_TEST_ACCOUNT=natdeveloper
8
export WAX_TEST_ENDPOINT=https://testnet.waxsweden.org
Copied!
  • Setup atomictokenpegeosio on the Kylin token contract Account and atomictokenpegxeosio on the Wax Testnet token contract Account using zeus migrate.
  • Import private keys
1
zeus key import $KYLIN_BRIDGE_ACCOUNT --owner-private-key 5JPPPML... --active-private-key 5KdLRibwg1v... --network=kylin
2
zeus key import $WAX_TEST_BRIDGE_ACCOUNT --owner-private-key 5KkDxt... --active-private-key 5KkDxtfyKQQ... --network=waxtest
Copied!
  • Create contract deployment files located in ./zeus_boxes/contract-migrations-extensions/models/contract-deployments/
1
zeus create contract-deployment atomictokenpegeosio $KYLIN_BRIDGE_ACCOUNT kylin
2
zeus create contract-deployment atomictokenpegxeosio $WAX_TEST_BRIDGE_ACCOUNT waxtest
Copied!
  • Migrate contracts to Kylin/Wax Testnet
Zeus Migrate
cleos set contract
1
zeus migrate atomictokenpegeosio --network=kylin --creator $KYLIN_BRIDGE_ACCOUNT --no-reset --no-compile-all --creator-key=""
2
zeus migrate atomictokenpegxeosio --network=waxtest --creator $WAX_TEST_BRIDGE_ACCOUNT --no-reset --no-compile-all --creator-key=""
Copied!
1
# if migration fails
2
cd contracts/eos
3
cleos -u $KYLIN_ENDPOINT set contract $KYLIN_BRIDGE_ACCOUNT atomictokenpegeosio
4
cleos -u $WAX_TEST_ENDPOINT set contract $WAX_TEST_BRIDGE_ACCOUNT atomictokenpegxeosio
Copied!
Initialize token contracts
  • Create NFTs on Kylin
For Kylin we'll setup the collection and schema then mint an asset to the test contract. If you have a pre existing NFT, you can send it to the Kylin test account.
On WAX Test we'll also setup the collection/schema, but we'll make the bridge contract a authorized account on the collection so it can mint new NFTs.
Kylin
Wax Testnet
1
export AUTHOR=$KYLIN_TEST_ACCOUNT
2
export COLLECTION_NAME=nftauthcolll # create a different one because this one's taken
3
export ALLOW_NOTIFY=1
4
export AUTHORIZED_ACCOUNTS=[$KYLIN_TEST_ACCOUNT] # add additional accounts if necessary
5
export NOTIFY_ACCOUNTS=[""]
6
export MARKET_FEE=0.01 # cause we're fair people
7
export DATA=[]
8
export SCHEMA_NAME=nftauthschem
9
export SCHEMA_FORMAT=[ {name: "name", type: "string"}, {name: "series", type: "string"}, {name: "moment", type: "string"}, {name: "description", type: "string"}, {name: "img", type: "image"}, {name: "backimg", type: "string"}, {name: "rarity", type: "string"} ]
10
# not working, if you know how to make it (passing array as variable) work, please edit!!
11
# cleos -u $KYLIN_ENDPOINT push action $KYLIN_TOKEN_ACCOUNT createcol "[\"$AUTHOR\",\"$COLLECTION_NAME\",\"$ALLOW_NOTIFY\",\"$AUTHORIZED_ACCOUNTS\",\"$NOTIFY_ACCOUNTS\",\"$MARKET_FEE\",\"$DATA\"]" -p [email protected]
12
​
13
# create collection
14
cleos -u $KYLIN_ENDPOINT push transaction '{
15
"delay_sec": 0,
16
"max_cpu_usage_ms": 0,
17
"actions": [
18
{
19
"account": "bridgeassets",
20
"name": "createcol",
21
"data": {
22
"author": "natdeveloper",
23
"collection_name": "nftauthcolll",
24
"allow_notify": true,
25
"authorized_accounts": [
26
"natdeveloper"
27
],
28
"notify_accounts": [],
29
"market_fee": 0.01,
30
"data": []
31
},
32
"authorization": [
33
{
34
"actor": "natdeveloper",
35
"permission": "active"
36
}
37
]
38
}
39
]
40
}'
41
​
42
# create schema
43
cleos -u $KYLIN_ENDPOINT push transaction '{
44
"delay_sec": 0,
45
"max_cpu_usage_ms": 0,
46
"actions": [
47
{
48
"account": "bridgeassets",
49
"name": "createschema",
50
"data": {
51
"authorized_creator": "natdeveloper",
52
"collection_name": "nftauthcolll",
53
"schema_name": "nftauthschem",
54
"schema_format": [
55
{
56
"name": "name",
57
"type": "string"
58
},
59
{
60
"name": "series",
61
"type": "string"
62
},
63
{
64
"name": "moment",
65
"type": "string"
66
},
67
{
68
"name": "description",
69
"type": "string"
70
},
71
{
72
"name": "img",
73
"type": "image"
74
},
75
{
76
"name": "backimg",
77
"type": "string"
78
},
79
{
80
"name": "rarity",
81
"type": "string"
82
}
83
]
84
},
85
"authorization": [
86
{
87
"actor": "natdeveloper",
88
"permission": "active"
89
}
90
]
91
}
92
]
93
}'
Copied!
1
export AUTHOR=$WAX_TEST_TEST_ACCOUNT
2
export COLLECTION_NAME=nftauthcolll # create a different one because this one's taken
3
export ALLOW_NOTIFY=1
4
export AUTHORIZED_ACCOUNTS=[$WAX_TEST_BRIDGE_ACCOUNT] # add additional accounts if necessary
5
export NOTIFY_ACCOUNTS=[]
6
export MARKET_FEE=0.01 # cause we're fair people
7
export DATA=[]
8
cleos -u $WAX_TEST_ENDPOINT push action $WAX_TEST_TOKEN_ACCOUNT createcol "[\"$AUTHOR\",\"$COLLECTION_NAME\",\"$ALLOW_NOTIFY\",\"$AUTHORIZED_ACCOUNTS\",\"$NOTIFY_ACCOUNTS\",\"$MARKET_FEE\",\"$DATA\"]" -p $WAX_TEST_TEST_ACCOUNT@active
9
​
10
cleos -u $WAX_TEST_ENDPOINT push transaction '{
11
"delay_sec": 0,
12
"max_cpu_usage_ms": 0,
13
"actions": [
14
{
15
"account": "atomicassets",
16
"name": "createcol",
17
"data": {
18
"author": "natdeveloper",
19
"collection_name": "nftauthcolll",
20
"allow_notify": true,
21
"authorized_accounts": [
22
"natdeveloper",
23
"atomicbridg1"
24
],
25
"notify_accounts": [],
26
"market_fee": 0.01,
27
"data": []
28
},
29
"authorization": [
30
{
31
"actor": "natdeveloper",
32
"permission": "active"
33
}
34
]
35
}
36
]
37
}'
38
​
39
# create schema
40
cleos -u $WAX_TEST_ENDPOINT push transaction '{
41
"delay_sec": 0,
42
"max_cpu_usage_ms": 0,
43
"actions": [
44
{
45
"account": "atomicassets",
46
"name": "createschema",
47
"data": {
48
"authorized_creator": "natdeveloper",
49
"collection_name": "nftauthcolll",
50
"schema_name": "nftauthschem",
51
"schema_format": [
52
{
53
"name": "name",
54
"type": "string"
55
},
56
{
57
"name": "series",
58
"type": "string"
59
},
60
{
61
"name": "moment",
62
"type": "string"
63
},
64
{
65
"name": "description",
66
"type": "string"
67
},
68
{
69
"name": "img",
70
"type": "image"
71
},
72
{
73
"name": "backimg",
74
"type": "string"
75
},
76
{
77
"name": "rarity",
78
"type": "string"
79
}
80
]
81
},
82
"authorization": [
83
{
84
"actor": "natdeveloper",
85
"permission": "active"
86
}
87
]
88
}
89
]
90
}'
Copied!
If you get errors such as Transaction exceeded the current network usage limit imposed on the transaction, see the Kylin / Wax Testnet account setup guides to get more tokens and to stake for more resources.
  • Mint test tokens
We will mint some test NFT tokens to our test account.
Be sure to update the account name, the new asset owner, the collection name and the actor signing the transaction.
1
export AUTHORIZED_MINTER=$KYLIN_TEST_ACCOUNT
2
export COLLECTION_NAME=$COLLECTION_NAME
3
export SCHEMA_NAME=$SCHEMA_NAME
4
export TEMPLATE_ID=-1
5
export NEW_ASSET_OWNER=$KYLIN_TEST_ACCOUNT
6
export IMMUTABLE_DATA=[ { "key": "name", "value": [ "string", "The New Silk Road" ] }, { "key": "img", "value": [ "string", "QmSXDsFeNaPa3CJKmn8WKBnA421Zv5r3Ra8n71LZhvEi9s/main/genesis/1.png" ] }, { "key": "backimg", "value": [ "string", "QmSXDsFeNaPa3CJKmn8WKBnA421Zv5r3Ra8n71LZhvEi9s/main/genesis/1_back.jpg" ] }, { "key": "series", "value": [ "string", "Through the Looking Glass" ] }, { "key": "moment", "value": [ "string", "6 - The Silk Road" ] }, { "key": "rarity", "value": [ "string", "genesis" ] }, { "key": "description", "value": [ "string", "Named after an ancient Chinese trade route, the digital silk road is a virtual pathway for the delivery of merchandise." ] } ]
7
export MUTABLE_DATA=[]
8
export TOKENS_TO_BACK=[]
9
​
10
cleos -u $KYLIN_ENDPOINT push transaction '{
11
"delay_sec": 0,
12
"max_cpu_usage_ms": 0,
13
"actions": [
14
{
15
"account": "bridgeassets",
16
"name": "mintasset",
17
"data": {
18
"authorized_minter": "natdeveloper",
19
"collection_name": "nftauthcolll",
20
"schema_name": "nftauthschem",
21
"template_id": -1,
22
"new_asset_owner": "natdeveloper",
23
"immutable_data": [ { "key": "name", "value": [ "string", "The New Silk Road" ] }, { "key": "img", "value": [ "string", "QmSXDsFeNaPa3CJKmn8WKBnA421Zv5r3Ra8n71LZhvEi9s/main/genesis/1.png" ] }, { "key": "backimg", "value": [ "string", "QmSXDsFeNaPa3CJKmn8WKBnA421Zv5r3Ra8n71LZhvEi9s/main/genesis/1_back.jpg" ] }, { "key": "series", "value": [ "string", "Through the Looking Glass" ] }, { "key": "moment", "value": [ "string", "6 - The Silk Road" ] }, { "key": "rarity", "value": [ "string", "genesis" ] }, { "key": "description", "value": [ "string", "Named after an ancient Chinese trade route, the digital silk road is a virtual pathway for the delivery of merchandise." ] } ],
24
"mutable_data": [],
25
"tokens_to_back": []
26
},
27
"authorization": [
28
{
29
"actor": "natdeveloper",
30
"permission": "active"
31
}
32
]
33
}
34
]
35
}'
Copied!
  • Register mapping
The collection author for an NFT must register that NFT with the bridge before users can transfer.
1
cleos -u $KYLIN_ENDPOINT push transaction '{
2
"delay_sec": 0,
3
"max_cpu_usage_ms": 0,
4
"actions": [
5
{
6
"account": "atomicbridg1",
7
"name": "regmapping",
8
"data": {
9
"template_id": -1,
10
"schema_name": "nftauthschem",
11
"collection_name": "nftauthcolll",
12
"immutable_data": [ { "key": "name", "value": [ "string", "The New Silk Road" ] }, { "key": "img", "value": [ "string", "QmSXDsFeNaPa3CJKmn8WKBnA421Zv5r3Ra8n71LZhvEi9s/main/genesis/1.png" ] }, { "key": "backimg", "value": [ "string", "QmSXDsFeNaPa3CJKmn8WKBnA421Zv5r3Ra8n71LZhvEi9s/main/genesis/1_back.jpg" ] }, { "key": "series", "value": [ "string", "Through the Looking Glass" ] }, { "key": "moment", "value": [ "string", "6 - The Silk Road" ] }, { "key": "rarity", "value": [ "string", "genesis" ] }, { "key": "description", "value": [ "string", "Named after an ancient Chinese trade route, the digital silk road is a virtual pathway for the delivery of merchandise." ] } ],
13
},
14
"authorization": [
15
{
16
"actor": "natdeveloper",
17
"permission": "active"
18
}
19
]
20
}
21
]
22
}'
Copied!
Now that we've prepared that part let's move onto staking DAPP for services. First stop is the faucet for some DAPP tokens here. Use the account that has the atomictokenpegeosio contract set to it ($KYLIN_BRIDGE_ACCOUNT).
  • Stake to required services vRAM, LiquidHarmony Oracles, and LiquidScheduler
Using the DSP Portal we can see these packages:
Below we'll select each package then stake for it.
vRAM
LiquidHarmony
LiquidScheduler
1
export PROVIDER=heliosselene
2
export PACKAGE=ipfs1
3
export SERVICE=ipfsservice1
4
export QUANTITY="10.0000 DAPP"
5
cleos -u $KYLIN_ENDPOINT push action dappservices selectpkg "[\"$KYLIN_BRIDGE_ACCOUNT\",\"$PROVIDER\",\"$SERVICE\",\"$PACKAGE\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
6
cleos -u $KYLIN_ENDPOINT push action dappservices stake "[\"$KYLIN_BRIDGE_ACCOUNT\",\"$PROVIDER\",\"$SERVICE\",\"$QUANTITY\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
Copied!
1
export PROVIDER=heliosselene
2
export PACKAGE=xpackage
3
export SERVICE=oracleservic
4
export QUANTITY="10.0000 DAPP"
5
cleos -u $KYLIN_ENDPOINT push action dappservices selectpkg "[\"$KYLIN_BRIDGE_ACCOUNT\",\"$PROVIDER\",\"$SERVICE\",\"$PACKAGE\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
6
cleos -u $KYLIN_ENDPOINT push action dappservices stake "[\"$KYLIN_BRIDGE_ACCOUNT\",\"$PROVIDER\",\"$SERVICE\",\"$QUANTITY\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
Copied!
1
export PROVIDER=heliosselene
2
export PACKAGE=cronservices
3
export SERVICE=cronservices
4
export QUANTITY="10.0000 DAPP"
5
cleos -u $KYLIN_ENDPOINT push action dappservices selectpkg "[\"$KYLIN_BRIDGE_ACCOUNT\",\"$PROVIDER\",\"$SERVICE\",\"$PACKAGE\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
6
cleos -u $KYLIN_ENDPOINT push action dappservices stake "[\"$KYLIN_BRIDGE_ACCOUNT\",\"$PROVIDER\",\"$SERVICE\",\"$QUANTITY\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
Copied!
  • LiquidX stake
In order to stake for services on WAX Testnet, a LiquidX mapping must be created, for more detail see here.
Kylin
WAX Testnet setlink
WAX Testnet add dsp
1
export OWNER=$KYLIN_BRIDGE_ACCOUNT
2
export CHAIN_ACCOUNT=$WAX_TEST_BRIDGE_ACCOUNT
3
export CHAIN_NAME=liquidxxtwax
4
cleos -u $KYLIN_ENDPOINT push action liquidxxxxxx addaccount "[\"$OWNER\",\"$CHAIN_ACCOUNT\",\"$CHAIN_NAME\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
Copied!
1
export OWNER=$WAX_TEST_BRIDGE_ACCOUNT
2
export MAINNET_OWNER=$KYLIN_BRIDGE_ACCOUNT
3
cleos -u $WAX_TEST_ENDPOINT push action dappservicex setlink "[\"$OWNER\",\"$MAINNET_OWNER\"]" -p $WAX_TEST_BRIDGE_ACCOUNT@active
Copied!
1
export OWNER=$WAX_TEST_BRIDGE_ACCOUNT
2
export DSP=$PROVIDER
3
cleos -u $WAX_TEST_ENDPOINT push action dappservicex adddsp "[\"$OWNER\",\"$DSP\"]" -p $WAX_TEST_BRIDGE_ACCOUNT@active
Copied!
  • Initialize
Here we will initialize both bridges with their settings. On Kylin we will not allow issuance because the token already exists. On WAX Testnet we allow the bridge contract to mint/burn. We set the minimum transfer to 1 TKN.
Kylin
WAX Testnet
1
export SISTER_CODE=$WAX_TEST_BRIDGE_ACCOUNT
2
export SISTER_CHAIN_NAME="waxtest"
3
export THIS_CHAIN_NAME="kylin"
4
export PROCESSING_ENABLED=1
5
export TOKEN_CONRACT=$KYLIN_TOKEN_ACCOUNT
6
export TRANSFERS_ENABLED=1
7
export CAN_ISSUE=0
8
export KYLIN_DSP_ENDPOINT=http://kylin-dsp-2.liquidapps.io
9
cleos -u $KYLIN_ENDPOINT push action $KYLIN_BRIDGE_ACCOUNT init "[\"$SISTER_CODE\",\"$SISTER_CHAIN_NAME\",\"$THIS_CHAIN_NAME\",\"$PROCESSING_ENABLED\",\"$TOKEN_CONRACT\",\"$TRANSFERS_ENABLED\",\"$CAN_ISSUE\"]" -p $KYLIN_BRIDGE_ACCOUNT@active
Copied!
1
export SISTER_CODE=$KYLIN_BRIDGE_ACCOUNT
2
export SISTER_CHAIN_NAME="kylin"
3
export THIS_CHAIN_NAME="waxtest"
4
export PROCESSING_ENABLED=1
5
export TOKEN_CONRACT=$WAX_TEST_TOKEN_ACCOUNT
6
export TRANSFERS_ENABLED=1
7
export CAN_ISSUE=1
8
cleos -u $WAX_TEST_ENDPOINT push action $WAX_TEST_BRIDGE_ACCOUNT init "[\"$SISTER_CODE\",\"$SISTER_CHAIN_NAME\",\"$THIS_CHAIN_NAME\",\"$PROCESSING_ENABLED\",\"$TOKEN_CONRACT\",\"$TRANSFERS_ENABLED\",\"$CAN_ISSUE\"]" -p $WAX_TEST_BRIDGE_ACCOUNT@active
Copied!
  • Transfer
Now we will test with a transfer from the Kylin example user to the Kylin bridge contract, let's see how it goes!!
Kylin
1
export FROM=$KYLIN_TEST_ACCOUNT
2
export TO=$KYLIN_BRIDGE_ACCOUNT
3
export ASSET_ID=1099511627776
4
# destionation_account,destination_chain
5
# this is required as the memo type, it tells the bridge which chain the funds go to and who gets them
6
export MEMO="$WAX_TEST_TEST_ACCOUNT,$CHAIN_NAME"
7
cleos -u $KYLIN_ENDPOINT push action $KYLIN_TOKEN_ACCOUNT transfer "[\"$FROM\",\"$TO\",[\"$ASSET_ID\"],\"$MEMO\"]" -p $KYLIN_TEST_ACCOUNT@active
Copied!
  • Confirm
If all goes well you will see the tokens arrive at your WAX Testnet destination account, you can send them back to the bridge contract now to send them back!
WAX Testnet
1
export FROM=$WAX_TEST_TEST_ACCOUNT
2
export TO=$WAX_TEST_BRIDGE_ACCOUNT
3
export ASSET_ID=1099511627776
4
# destionation_account,destination_chain
5
# this is required as the memo type, it tells the bridge which chain the funds go to and who gets them
6
export MEMO="$KYLIN_TEST_ACCOUNT,kylin"
7
cleos -u $WAX_TEST_ENDPOINT push action $WAX_TEST_TOKEN_ACCOUNT transfer "[\"$FROM\",\"$TO\",[\"$ASSET_ID\"],\"$MEMO\"]" -p $WAX_TEST_TEST_ACCOUNT@active
Copied!
Note that the memo destination chain is now kylin and no longer liquidxxtwax because we are sending the tokens to kylin.
If the transfers are not going through, ensure that the DSP you are using has enough CPU/NET staked for it
​
Last modified 4mo ago
Copy link