Skip to content

Latest commit

 

History

History
461 lines (353 loc) · 23 KB

母子链货币交互简介.rst

File metadata and controls

461 lines (353 loc) · 23 KB

母子链货币交互简介

墨客支持有币子链,并且提供母链货币和子链原生币之间的兑换(充提)。

当前,墨客提供三种类型的母子链货币交互,以下一一介绍

母链MOAC和子链原生币交互

这个是最基础的一种货币兑换。使用者可以在主链上充值MOAC,然后最早在下一个flush周期在子链上获取子链原生币。同理,使用者可以提出子链原生币,并最早在下一个flush周期获得主链MOAC。

子链部署准备

参考子链部署章节,完成部署子链的准备工作。 :: 子链操作账号: 0x87e369172af1e817ebd8d63bcd9f685a513a6736 vnode矿池合约地址: 0x22f141dcc59850707708bc90e256318a5fe0b928 vnode代理地址: 0xf103bc1c054babcecd13e7ac1cf34f029647b08c 192.168.10.209:50062 子链矿池合约地址: 0xe42f4f566aedc3b6dd61ea4f70cc78d396130fac scs0: 0x075447a6df1fde4f39243bc67a945312ff36c193 确保启动并加入子链矿池 scs1: 0x7932f827c90c5f06c0177f642a07edfa73ee3044 确保启动并加入子链矿池 scs monitor: 0xa5966600efb221097ce6a8ba1dc6eb1d5b43ef83

erc20 部署

这类似一个管理合约,负责和子链货币之间的转换

参考官方示例的erc20合约DirectExchangeToken.sol 调用示例: 注意参数 tokensupply为erc20 的token总量,exchangerate为moac与子链token的兑换比率 :: > chain3 = require('chain3') > solc = require('solc') > chain3 = new chain3(); > chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); > input = {'': fs.readFileSync('DirectExchangeToken.sol', 'utf8'), 'StandardToken.sol': fs.readFileSync('StandardToken.sol', 'utf8'), 'ERC20.sol': fs.readFileSync('ERC20.sol', 'utf8'), 'SafeMath.sol': fs.readFileSync('SafeMath.sol', 'utf8')}; > output = solc.compile({sources: input}, 1); > abi = output.contracts[':DirectExchangeToken'].interface; > bin = output.contracts[':DirectExchangeToken'].bytecode; > tokensupply = 100000000; // total supply > exchangerate = 100; > directexchangetokenContract = chain3.mc.contract(JSON.parse(abi)); > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > dtoken = directexchangetokenContract.new( tokensupply, exchangerate,{ from: chain3.mc.accounts[0], data: '0x' + bin, gas:'9000000'} , function (e, contract){console.log('Contract address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); });

部署完毕后, 获得erc20合约地址 0x5fcb383cf80a9d2961f4d8ba0a4b9e4a34157da7

subchainbase 部署

注意这个子链合约在官方基础上进行了修改,增加了setToken和MintToken相关的若干方法。 部署SubChainBase.sol示例: :: > chain3 = require('chain3') > solc = require('solc') > chain3 = new chain3(); > chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); > input = {'': fs.readFileSync('SubChainBase.sol', 'utf8'), 'SubChainProtocolBase.sol': fs.readFileSync('SubChainProtocolBase.sol', 'utf8')}; > output = solc.compile({sources: input}, 1); > abi = output.contracts[':SubChainBase'].interface; > bin = output.contracts[':SubChainBase'].bytecode; > proto = '0xe42f4f566aedc3b6dd61ea4f70cc78d396130fac' ; // 子链矿池合约 > vnodeProtocolBaseAddr = '0x22f141dcc59850707708bc90e256318a5fe0b928' ; // Vnode矿池合约 > min = 1 ; // 子链需要SCS的最小数量 > max = 10 ; // 子链需要SCS的最大数量 > thousandth = 1 ; // 千分之几 > flushRound = 40 ; // 子链刷新周期 单位是主链block生成对应数量的时间(10秒一个block) > SubChainBaseContract = chain3.mc.contract(JSON.parse(abi)); > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > SubChainBase = SubChainBaseContract.new( proto, vnodeProtocolBaseAddr, min, max, thousandth, flushRound,{ from: chain3.mc.accounts[0], data: '0x' + bin, gas:'9000000'} , function (e, contract){console.log('Contract address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); });

部署完毕后, 获得子链合约地址 0xe9463e215315d6f1e5387a161868d7d0a4db89e8

ERC20 初始化

在子链的register open前先调用 subchainbase 的 setToken 方法
参数: DirectExchangeToken的合约地址
根据参数DirectExchangeToken的地址,实例化合约内部的DirectExchangeToke对象, 并将 DirectExchangeToken合约的totalsupply复制给合约变量 BALANCE

调用示例: :: 根据ABI chain3.sha3("setToken(address)") = 0x144fa6d7f374f07750ac69fe5e8b4f8a614ab02482bcb9f0fa3f2c98943860c6 取前4个字节 0x144fa6d7 参数传erc20合约地址 5fcb383cf80a9d2961f4d8ba0a4b9e4a34157da7 (前面补24个0, 凑足32个字节) 0x144fa6d70000000000000000000000005fcb383cf80a9d2961f4d8ba0a4b9e4a34157da7 > subchainaddr = '0xe9463e215315d6f1e5387a161868d7d0a4db89e8'; > data = '0x144fa6d70000000000000000000000005fcb383cf80a9d2961f4d8ba0a4b9e4a34157da7' > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: data});

验证:

访问子链合约的 BALANCE 为 ERC20的 totalsupply :: > chain3.mc.getStorageAt(subchainaddr,0x30) // 注意BALANCE变量在合约中变量定义的位置(16进制)

然后调用DirectExchangeToken 的 updateOwner 方法 将 合约owner由发布者 改为 subchainbase地址 这样子链合约就可以操控ERC20合约,并进行方法调用。 :: 根据ABI chain3.sha3('updateOwner(address)') = 0x880cdc3156e7a1d7441d29b6ec3cab090473e3e84f7cc83d0bdcd0a696e8064b 取前4个字节 0x880cdc31 参数传subchainbase合约地址 e9463e215315d6f1e5387a161868d7d0a4db89e8 (前面补24个0, 凑足32个字节) 0x880cdc31000000000000000000000000e9463e215315d6f1e5387a161868d7d0a4db89e8 > erc20addr = '0x5fcb383cf80a9d2961f4d8ba0a4b9e4a34157da7'; > data = '0x880cdc31000000000000000000000000e9463e215315d6f1e5387a161868d7d0a4db89e8' > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: erc20addr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: data});

验证:

访问erc20合约的 owner 是否由部署账号 0x87e369172af1e817ebd8d63bcd9f685a513a6736 改为 子链合约地址 0xe9463e215315d6f1e5387a161868d7d0a4db89e8 :: > chain3.mc.getStorageAt(erc20addr,0x03) // 注意owner变量在合约中变量定义的位置(16进制)

子链注册scs

子链开放注册

调用合约里的函数addFund :: 根据ABI chain3.sha3("addFund()") = 0xa2f09dfa891d1ba530cdf00c7c12ddd9f6e625e5368fff9cdf23c9dc0ad433b1 取前4个字节 0xa2f09dfa > amount = 20; > subchainaddr = '0xe9463e215315d6f1e5387a161868d7d0a4db89e8'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:chain3.toSha(amount,'mc'), to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0xa2f09dfa'});

可以通过查询余额进行验证 :: > chain3.mc.getBalance('0xe9463e215315d6f1e5387a161868d7d0a4db89e8')

然后调用 调用合约里的函数registerOpen 开放注册 (按子链矿池合约中SCS注册先后排序进行选取) :: 根据ABI chain3.sha3("registerOpen()") = 0x5defc56ce78f178d760a165a5528a8e8974797e616a493970df1c0918c13a175 取前4个字节 0x5defc56c > subchainaddr = '0xe9463e215315d6f1e5387a161868d7d0a4db89e8'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x5defc56c'});

验证:

访问子链合约的 nodeCount :: > chain3.mc.getStorageAt(subchainaddr,0x0e) // 注意nodeCount变量在合约中变量定义的位置(16进制)

等到两个scs都注册完毕后,即注册SCS数目大于等于子链要求的最小数目时,调用子链合约里的函数 registerClose关闭注册 :: 根据ABI chain3.sha3("registerClose()") = 0x69f3576fc10c82561bd84b0045ee48d80d59a866174f2513fdef43d65702bf70 取前4个字节 0x69f3576f > subchainaddr = '0xe9463e215315d6f1e5387a161868d7d0a4db89e8'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x69f3576f'});

验证:

访问子链合约的 registerFlag 为 0 :: > chain3.mc.getStorageAt(subchainaddr,0x14) // 注意registerFlag变量在合约中变量定义的位置(16进制)

同时观察scs的concole界面,scs开始出块即成功完成部署子链。

dapp合约部署

部署 dapp合约,dechat是一个官方示例,注意合约有两个参数,分别是版主的账号和开发者的账号

部署示例: :: > chain3 = require('chain3') > solc = require('solc') > chain3 = new chain3(); > chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); > solfile = 'dechat1.0.5.sol'; > contract = fs.readFileSync(solfile, 'utf8'); > output = solc.compile(contract, 1); > abi = output.contracts[':DeChat'].interface; > bin = output.contracts[':DeChat'].bytecode; > bin += '000000000000000000000000' + '87e369172af1e817ebd8d63bcd9f685a513a6736'; // 版主的账号 > bin += '000000000000000000000000' + '87e369172af1e817ebd8d63bcd9f685a513a6736'; // 开发者的账号 > amount = chain3.toSha(100000000,'mc') // 要与部署DirectExchangeToken合约地址的amount参数一致 > subchainaddr = '0xe9463e215315d6f1e5387a161868d7d0a4db89e8'; > via = '0xf103bc1c054babcecd13e7ac1cf34f029647b08c'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction({from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas:0, shardingFlag: "0x1", data: '0x' + bin, nonce: 0, via: via, });

验证:
合约部署成功后,Nonce值应该是1

dapp 充值

调用 subchainbase 的 buyMintToken方法充值, 用户账号为发出sendTransaction的账号 数量为sendTransaction的amount参数
buyMintToken方法首先调用 DirectExchangeToke对象 的 buyMintToken 方法 按交易记录的amount 扣除DirectExchangeToke合约本身的token数量,增加用户账号对应token的数量
然后调用 transfer 给DirectExchangeToken合约地址 转 对应的moac
再调用 DirectExchangeToke对象 的 requestEnterMicrochain方法 (传subchainbase地址和对应token数量),减去用户账号地址的对应token数量, 增加DirectExchangeToke合约本身的token总量
最后将用户账号和对应token数量,加入推送结构体发至子链,等待一轮flush后,充值会进入到子链

调用示例: :: 根据ABI chain3.sha3("buyMintToken()") = 0x6bbded701cd78dee9626653dc2b2e76d3163cc5a6f81ac3b8e69da6a057824cb 取前4个字节 0x6bbded70 > amount = 100; > subchainaddr = '0xe9463e215315d6f1e5387a161868d7d0a4db89e8'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value: chain3.toSha(amount,'mc'), to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x6bbded70'});

验证:
检查账号的moac是否减少: > chain3.mc.getBalance(chain3.mc.accounts[0])
检查子链的token是否增加: 调用monitor的方法 ScsRPCMethod.GetBalance 获得子链token

dapp 提币

调用 dapp合约 的 redeemFromMicroChain方法, 用户账号为发出sendTransaction的账号 数量为sendTransaction的amount参数
redeemFromMicroChain方法将用户账号和对应token数量加入推送结构体redeem,等待一轮flush后,自动会调用子链合约的redeemFromMicroChain方法
然后子链合约自动调用DirectExchangeToke对象的 redeemFromMicroChain 方法,扣除DirectExchangeToke合约本身的token数量,增加用户账号对应token的数量
最后自动调用subchainbase的sellMintToken 方法,自动调用DirectExchangeToke对象的 sellMintToken 兑换moac

调用示例: :: 根据ABI chain3.sha3("redeemFromMicroChain()") = 0x89739c5bf1ef36273bf0e7aeb59ffe71213a58e1f01965e75662cb21b03abb13 取前4个字节 0x89739c5b > nonce = 1 // 调用ScsRPCMethod.GetNonce获得 > subchainaddr = '0x1195cd9769692a69220312e95192e0dcb6a4ec09'; > via = '0xf103bc1c054babcecd13e7ac1cf34f029647b08c'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { nonce: nonce, from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas:0, shardingFlag:'0x1', data: '0x89739c5b', via: via,});

验证:
检查账号的moac是否增加: > chain3.mc.getBalance(chain3.mc.accounts[0])
检查子链的token是否减少: 调用monitor的方法 ScsRPCMethod.GetBalance 获得子链token

母链ERC20和子链原生币交互

这是非常通用的一种货币兑换。使用者可以使用预先已经部署好的ERC20,或者当场部署一个主链ERC20,和子链的原生币进行兑换。

子链部署准备

参考子链部署章节,完成部署子链的准备工作。 :: 子链操作账号: 0x87e369172af1e817ebd8d63bcd9f685a513a6736 vnode矿池合约地址: 0x22f141dcc59850707708bc90e256318a5fe0b928 vnode代理地址: 0xf103bc1c054babcecd13e7ac1cf34f029647b08c 192.168.10.209:50062 子链矿池合约地址: 0xe42f4f566aedc3b6dd61ea4f70cc78d396130fac scs0: 0xd81043d85c9c959d2925958c54c1a49c7bfd1fc8 确保启动并加入子链矿池 scs1: 0xe767059d768fcef12e527fab63fda68cc13e24b3 确保启动并加入子链矿池 scs monitor: 0x0964e5d73d6a40f2fc707aa3e1361028a34923f0

erc20 部署

默认一个标准的erc20合约,通过allowance,transferFrom,balanceOf,transfer等标准的方法支持货币的转移。

参考官方示例的erc20合约erc20.sol,默认decimals为6,totalSupply为100000000乘以10的6次方。 调用示例: :: > chain3 = require('chain3') > solc = require('solc') > chain3 = new chain3(); > chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); > solfile = 'erc20.sol'; > contract = fs.readFileSync(solfile, 'utf8'); > output = solc.compile(contract, 1); > abi = output.contracts[':TestCoin'].interface; > bin = output.contracts[':TestCoin'].bytecode; > erc20Contract = chain3.mc.contract(JSON.parse(abi)); > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > dtoken = erc20Contract.new( { from: chain3.mc.accounts[0], data: '0x' + bin, gas:'9000000'} , function (e, contract){console.log('Contract address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); });

部署完毕后, 获得erc20合约地址 0x5042086887a86151945d2c2bb60628addf49d48c

验证: 调用合约balanceOf方法查询部署者的余额,应该是10的14次方

> contractInstance = erc20Contract.at('0x5042086887a86151945d2c2bb60628addf49d48c') > contractInstance.balanceOf.call('0x87e369172af1e817ebd8d63bcd9f685a513a6736')

subchainbase 部署

注意这个子链合约在官方基础上进行了修改,增加了erc20合约地址和兑换比例的参数 部署SubChainBase.sol示例: :: > chain3 = require('chain3') > solc = require('solc') > chain3 = new chain3(); > chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); > input = {'': fs.readFileSync('SubChainBase.sol', 'utf8'), 'SubChainProtocolBase.sol':fs.readFileSync('SubChainProtocolBase.sol', 'utf8')}; > output = solc.compile({sources: input}, 1); > abi = output.contracts[':SubChainBase'].interface; > bin = output.contracts[':SubChainBase'].bytecode; > proto = '0xe42f4f566aedc3b6dd61ea4f70cc78d396130fac' ; // 子链矿池合约 > vnodeProtocolBaseAddr = '0x22f141dcc59850707708bc90e256318a5fe0b928' ; // Vnode矿池合约 > ercAddr = '0x5042086887a86151945d2c2bb60628addf49d48c'; // erc20合约地址 > ercRate = 100; // 兑换比率 > min = 1 ; // 子链需要SCS的最小数量 > max = 10 ; // 子链需要SCS的最大数量 > thousandth = 1 ; // 千分之几 > flushRound = 40 ; // 子链刷新周期 单位是主链block生成对应数量的时间(10秒一个block) > SubChainBaseContract = chain3.mc.contract(JSON.parse(abi)); > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > SubChainBase = SubChainBaseContract.new( proto, vnodeProtocolBaseAddr, ercAddr, ercRate, min, max, thousandth, flushRound,{ from: chain3.mc.accounts[0], data: '0x' + bin, gas:'9000000'} , function (e, contract){console.log('Contract address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); });

部署完毕后, 获得子链合约地址 0xb877bf4e4cc94fd9168313e00047b77217760930

验证:

访问子链合约的 BALANCE 为 ERC20的 totalsupply :: > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > chain3.mc.getStorageAt(subchainaddr,0x30) // 注意BALANCE变量在合约中变量定义的位置(16进制) 1ed09bead87c0378d8e6400000000 应该是10的34次方 (14 + 2 + 18)

子链注册scs

子链开放注册

调用合约里的函数addFund :: 根据ABI chain3.sha3("addFund()") = 0xa2f09dfa891d1ba530cdf00c7c12ddd9f6e625e5368fff9cdf23c9dc0ad433b1 取前4个字节 0xa2f09dfa > amount = 20; > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:chain3.toSha(amount,'mc'), to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0xa2f09dfa'});

可以通过查询余额进行验证 :: > chain3.mc.getBalance('0xb877bf4e4cc94fd9168313e00047b77217760930')

然后调用 调用合约里的函数registerOpen 开放注册 (按子链矿池合约中SCS注册先后排序进行选取) :: 根据ABI chain3.sha3("registerOpen()") = 0x5defc56ce78f178d760a165a5528a8e8974797e616a493970df1c0918c13a175 取前4个字节 0x5defc56c > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x5defc56c'});

验证:

访问子链合约的 nodeCount :: > chain3.mc.getStorageAt(subchainaddr,0x0e) // 注意nodeCount变量在合约中变量定义的位置(16进制)

等到两个scs都注册完毕后,即注册SCS数目大于等于子链要求的最小数目时,调用子链合约里的函数 registerClose关闭注册 :: 根据ABI chain3.sha3("registerClose()") = 0x69f3576fc10c82561bd84b0045ee48d80d59a866174f2513fdef43d65702bf70 取前4个字节 0x69f3576f > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x69f3576f'});

验证:

访问子链合约的 registerFlag 为 0 :: > chain3.mc.getStorageAt(subchainaddr,0x14) // 注意registerFlag变量在合约中变量定义的位置(16进制)

同时观察scs的concole界面,scs开始出块即成功完成部署子链。

dapp合约部署

部署 dapp合约,dechat是一个官方示例,注意合约有两个参数,分别是版主的账号和开发者的账号

部署示例: :: > chain3 = require('chain3') > solc = require('solc') > chain3 = new chain3(); > chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); > solfile = 'dechat1.0.5.sol'; > contract = fs.readFileSync(solfile, 'utf8'); > output = solc.compile(contract, 1); > abi = output.contracts[':DeChat'].interface; > bin = output.contracts[':DeChat'].bytecode; > bin += '000000000000000000000000' + '87e369172af1e817ebd8d63bcd9f685a513a6736'; // 版主的账号 > bin += '000000000000000000000000' + '87e369172af1e817ebd8d63bcd9f685a513a6736'; // 开发者的账号 > amount = chain3.toSha(100000000,'mc') // dapp合约地址的token数量,与erc20的amount一致 > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > via = '0xf103bc1c054babcecd13e7ac1cf34f029647b08c'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction({from: chain3.mc.accounts[0], value:amount, to: subchainaddr, gas:0, shardingFlag: "0x1", data: '0x' + bin, nonce: 0, via: via, });

验证:
在 scs 的_logs目录下搜索日志文件,查找"created contract address",找到dapp合约地址:6ab296062d8a147297851719682fb5ffe081f1d3
调用monitor的方法 ScsRPCMethod.GetBalance 查询对应dapp合约地址的余额,应该等于erc20总量。

dapp 充值

调用 subchainbase 的 buyMintToken方法充值, 用户账号为发出sendTransaction的账号 ,参数分别为子链合约地址和token数量。
buyMintToken方法首先调用erc20合约的allowance检查授权,并调用transferFrom方法将token从用户账号地址转到合约地址
然后自动调用requestEnterMicrochain方法,将用户账号和对应token数量,加入推送结构体发至子链,等待一轮flush后,充值会进入到子链

调用示例: :: > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > data = contractInstance.buyMintToken.getData(subchainaddr, 100) > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value: 0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: data});

验证:
检查账号的erc20 token是否减少: 调用erc20合约的balanceOf方法
检查子链的token是否增加: 调用monitor的方法 ScsRPCMethod.GetBalance 获得子链token

dapp 提币

调用 dapp合约 的 redeemFromMicroChain方法, 用户账号为发出sendTransaction的账号 数量为sendTransaction的amount参数
redeemFromMicroChain方法将用户账号和对应token数量加入推送结构体redeem,等待一轮flush后,自动会调用子链合约的redeemFromMicroChain方法
调用erc20合约的transfer给用户账号转对应的token数量

调用示例: :: 根据ABI chain3.sha3("redeemFromMicroChain()") = 0x89739c5bf1ef36273bf0e7aeb59ffe71213a58e1f01965e75662cb21b03abb13 取前4个字节 0x89739c5b > nonce = 1 // 调用ScsRPCMethod.GetNonce获得 > subchainaddr = '0xb877bf4e4cc94fd9168313e00047b77217760930'; > via = '0xf103bc1c054babcecd13e7ac1cf34f029647b08c'; > chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456'); > chain3.mc.sendTransaction( { nonce: nonce, from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas:0, shardingFlag:'0x1', data: '0x89739c5b', via: via,});

验证:
检查账号的erc20 token是否增加: 调用erc20合约的balanceOf方法
检查子链的token是否减少: 调用monitor的方法 ScsRPCMethod.GetBalance 获得子链token

ATO方式

TODO