首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实心YUL-内联装配,访问双映射并对其进行升级

实心YUL-内联装配,访问双映射并对其进行升级
EN

Ethereum用户
提问于 2022-08-25 07:45:45
回答 1查看 294关注 0票数 1

你好,当我想要访问一个双映射时,我被yul内联程序集卡住了。

代码语言:javascript
复制
mapping(address => mapping(address => uint256)) public approval_;

function approve(address spender, uint256 amount) external returns (bool) {
assembly {
  // doc => https://docs.soliditylang.org/en/v0.8.9/internals/layout_in_storage.html
  // keccak(keccak(spender) => keccak(caller => approve slot))
  // load if user already approve this user
  let msgsender
  mstore(msgsender, caller()) // store msg.sender
  let spender_
  mstore(spender_, spender) // store spender

  let ptr := mload(0x40) // load free memory
  mstore(ptr, keccak256(spender_, 0x20)) // store hash spender
  mstore(add(ptr, 0x20), msgsender) // store msg.sender after spender hash
  mstore(add(ptr, 0x40), approval_.slot) // store approval slot after msg.sender
  let googHash := keccak256(add(ptr, 0x20), 0x40) // hash msg.sender + approval slot
  mstore(add(ptr, 0x20), googHash)
  let approveSlot := keccak256(ptr, 0x40) // hash => hash spender + hash msg.sender + approval slot
  let balanceApproved := sload(approveSlot) // load approve balance

  // store the new value
  sstore(approveSlot, add(balanceApproved, amount))
}
return true;

}

不明白我做错了什么,谢谢你的帮助;)

EN

回答 1

Ethereum用户

回答已采纳

发布于 2022-09-03 22:30:00

你几乎把一切都做对了,只有两个错误。

首先,当您将msg.senderspender分配给内存时。看看发生了什么

代码语言:javascript
复制
  let msgsender                  // msgsender = 0x00
  mstore(msgsender, caller())    // memory(0x00) = caller()
  let spender_                   // spender_ = 0x00
  mstore(spender_, spender)      // memory(0x00) = spender

基本上,对于这两个值,始终在槽0x00处使用内存,因此spender覆盖caller()

第二个错误是将值用作approval_[owner][spender]的时隙:

代码语言:javascript
复制
keccak(keccak(spender) . keccak(owner . approval_.slot))

正确的示例如下(请查看医生们中的示例):

代码语言:javascript
复制
keccak(spender . keccak(owner . approval_.slot))

把这一切结合起来,简化结构:

代码语言:javascript
复制
    mapping(address => mapping(address => uint256)) public approval_;

    function approve(address spender, uint256 amount) external returns (bool) {
      assembly {
        // compute keccak(owner . approval_.slot)
        mstore(0x00, caller())
        mstore(0x20, approval_.slot)
        let googHash := keccak256(0x00, 0x40) // hash msg.sender + approval slot
        
        // compute keccak(spender . googHash) -> this is the final slot
        // we can reuse the same memory
        mstore(0x00, spender)
        mstore(0x20, googHash)
        let approveSlot := keccak256(0x00, 0x40)
        
        // load approve balance
        let balanceApproved := sload(approveSlot)

        // store the new value
        sstore(approveSlot, add(balanceApproved, amount))
      }
      return true;
    }
票数 1
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/134326

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档