アルゴリズムとかオーダーとか

仕事で勉強したことなどをまとめてます

Solidityのassembly tips

Solidityでいろいろトリッキーなことを試す時にassemblyコードを書くのですが、毎回あれってどう書くんだっけ?ってなるので自分がよく使うassemblyコードをまとめておきます。

なお、template的な感じで書いてるのでこのままコピペしても動かないと思いますのでご注意ください。

free space pointerの再設定(assemblyブロックの後にコード続ける時は多分重要)

assembly {
  let freep := mload(0x40)
  let nextp := add(freep, 0x20) //  32byte開ける必要に応じて増減させてね
  mstore(0x40, nextp)
}

call,delegatecallのテンプレート(output 領域使いたい時に使う。)

address libaddr = 0x1234.....
bytes4 sig = bytes4(keccak256("funcname(uint256)"));
uint256 args = 10;
assembly {
  let freep := mload(0x40)
  let nextp := add(freep, 0x60)
  let outp := add(freep, 0x40)
  mstore(0x40, nextp)
  mstore(freep, sig)
  mstore(add(freep, 0x04), args)
  let length := add(0x04, 0x20) // sig 4byte + uint 32byte
  let res := delegatecall(sub(gas, 100000), libaddr, freep, length, outp, 0x20)
}

function signatureを4byteだけに縮める方法

bytes4 sig = bytes4(keccak256("hoge(uint256)")); // この時点ではメモリ上では32byteのまま
assembly {
  // divで先頭4byteだけ残した後mulでお尻を000...でうめる
  let sig4byte = mul(div(sig, 0x0100000000000000000000000000000000000000000000000000000000)0x0100000000000000000000000000000000000000000000000000000000)
}

function sigだけ変えてdelegatecallする

address libaddr = 0x1234.....
bytes4 sig = bytes4(keccak256("funcname(uint256)"));
assembly {
  let freep := mload(0x40)
  mstore(freep, sig)
  calldatacopy(add(freep, 0x04), 0x04, calldatasize) // calldataから引数部分だけコピーする
  let res := delegatecall(sub(gas, 10000), libaddr, freep, calldatasize, freep, 0x0) // outputは受け取らない
}