GasToken:我为何不再担心 gas 价格飙升(下)
(续前)GST2
free*
函数调用下列destroyChildren
实现:
function destroyChildren(uint256 value) internal {
uint256 tail = s_tail;
// tail points to slot behind the last contract in the queue
for (uint256 i = tail + 1; i <= tail + value; i++) {
mk_contract_address(this, i).call;
}
s_tail = tail + value;
}
此处 , 我们遍历 child 合约 , 并调用这些合约中的回调函数 。 正如 GST2 文档所指出的那样 , 发行代币时 , 合约必须找到 child 合约的创建地址(存储这些地址的成本会很高 , 因此我们会即时计算这些地址) 。 幸运的是 , 这是有可能做到的 , 因为使用 CREATE
生成的合约地址是根据地址/账户已创建的合约数量(nonce)计算得出的 , 具有确定性 。 这些合约地址都是在mk_contract_address
函数中计算得出的 , 在调用时无需任何参数或值 , 调用回调函数 , 然后就像在对应mint
函数中硬编码的那样 , gas 退款会发送至 parent 合约 。
CHI GasToken历时 3 年 , CHI GasToken 终于上线 。 CHI 由去中心化交易所聚合器 1inch.exchange 开发 , 与传统的 GasToken 类似 , 但是铸币效率比后者高出 1% , 释放代币的效率比后者高出 10% , 而且采用新的 CREATE2
操作码 。 该操作码可以提前通过确定性方式来创建链上合约地址 , 主要用于反事实的 Layer-2 解决方案 。
CREATE2
操作码采用 4 个堆栈参数:endowment、memory_start、memory_length 和盐值 。 生成地址等于keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]
, 而非常见的将发送方地址和 nonce 进行哈希计算 。 由于盐值控制在用户手中 , 用户可以提前知道地址 。
function mint(uint256 value) public {
uint256 offset = totalMinted;
assembly {
mstore(0, 0x746d4946c0e9F43F4Dee607b0eF1fA1c3318585733ff6000526015600bf30000)
for {let i := div(value, )} i {i := 32 sub((i, 1)} {
pop(create2(0, 0, 30, add(offset, 0))) pop(create2(0, 0, 30, add(offset, 1)))
pop(create2(0, 0, 30, add(offset, 2))) pop(create2(0, 0, 30, add(offset, 3)))
pop(create2(0, 0, 30, add(offset, 4))) pop(create2(0, 0, 30, add(offset, 5)))
pop(create2(0, 0, 30, add(offset, 6))) pop(create2(0, 0, 30, add(offset, 7)))
pop(create2(0, 0, 30, add(offset, 8))) pop(create2(0, 0, 30, add(offset, 9)))
pop(create2(0, 0, 30, add(offset, 10))) pop(create2(0, 0, 30, add(offset, 11)))
pop(create2(0, 0, 30, add(offset, 12))) pop(create2(0, 0, 30, add(offset, 13)))
pop(create2(0, 0, 30, add(offset, 14))) pop(create2(0, 0, 30, add(offset, 15)))
pop(create2(0, 0, 30, add(offset, 16))) pop(create2(0, 0, 30, add(offset, 17)))
pop(create2(0, 0, 30, add(offset, 18))) pop(create2(0, 0, 30, add(offset, 19)))
pop(create2(0, 0, 30, add(offset, 20))) pop(create2(0, 0, 30, add(offset, 21)))
pop(create2(0, 0, 30, add(offset, 22))) pop(create2(0, 0, 30, add(offset, 23)))
pop(create2(0, 0, 30, add(offset, 24))) pop(create2(0, 0, 30, add(offset, 25)))
pop(create2(0, 0, 30, add(offset, 26))) pop(create2(0, 0, 30, add(offset, 27)))
pop(create2(0, 0, 30, add(offset, 28))) pop(create2(0, 0, 30, add(offset, 29)))
pop(create2(0, 0, 30, add(offset, 30))) pop(create2(0, 0, 30, add(offset, 31)))
offset := add(offset, 32)
}
for {let i := and(value, 0x1F)} i {i := sub(i, 1)} {
pop(create2(0, 0, 30, offset))
offset := add(offset, 1)
}
}
_mint(msg.sender, value);
totalMinted = offset;
}
这里的一般流程是 , 将固定的 child 合约字节码存储到 memory 中(第 4 行代码) , 然后使用 for 循环反复调用
CREATE2
, 直到计算出对应的值为止 。 CREATE2
返回已部署 child 合约的地址 , 我们不关心这个地址 , 因此我们只是将这个地址从堆栈中弹出 。 偏移量计数器被用来计算 child 合约的数量 , 并将其永久存储在第 33 行代码中 。
对应的 free*
函数调用_destoryChildren
:
function _destroyChildren(uint256 value) internal {
assembly {
let i := sload(totalBurned_slot)
let end := add(i, value)
sstore(totalBurned_slot, end)
let data := mload(0x40)
mstore(data, 0xff0000000000004946c0e9F43F4Dee607b0eF1fA1c0000000000000000000000)
mstore(add(data, 53), 0x3c1644c68e5d6cb380c36d1bf847fdbc0c7ac28030025a2fc5e63cce23c16348)
let ptr := add(data, 21)
- 先别|用了周冬雨的照片,我会成为下一个被告?自媒体创作者先别自乱阵脚
- 当初|这是我的第一部华为手机,当初花6799元买的,现在“一文不值”?
- 发展|我省要求互联网平台坚持依法合规经营 推动线上经济健康规范发展
- 页面|流程图怎样画?老板要我帮他做个组织结构图
- 深度|iPhone12到底值得买吗 深度体验一周我发现了这些
- 效果|周冬雨化身美妆效果评测员?相比美妆数码宅的我更期待OPPO新机
- 退费|女子公众号上买菜,出现问题时已充上万元,公司:我们没有退费规矩
- 自助|新型通道-健康码自助核验闸机
- 环境|环境标识认知转盘游戏
- 手机壳里头|为什么要在手机壳里面夹钱?10个有9个不懂,我才知道大有讲究