# Totoro-BTC の支払いについて ###### tags: `Yellow paper` `Fee Payment` Totorollup では、オペレータへの手数料について次のアセットを使用することができる。 - Lightning-BTC - Lightning で受け取った生BTC - Totoro-BTC - Totoro 担保で作成した BTC - Totoro-ETH - Totoro 担保で作成した ETH これらのアセットは ERC20 として扱うため、実質的にオペレータは ERC20 を手数料として得ることができる。 ネイティブトークンとして扱う可能性については、面倒且つ複雑すぎるのでなしで。 ## 手数料決定アルゴリズム 手数料の上限/下限については決定されなければならない。またその手数料は Transactor が決めなければならない。理由としては不当な手数料の釣り上げができたり、オペレータが不正な state diff を設定できてしまうからである。 zkRollup ではトランザクションのシミューレーションコストが低く zkProof の作成コストが高いため、Base Fee が Contract Fee(L1におけるガス代)に対して高くなるように設定する。 そうすることで、比較的計算回数の多い(L1では多大なガス代が発生してしまうような)トランザクションに対し柔軟に対応できるようにする。 ここで、Base Fee はコントラクトの内容に寄らない(もしくは実行する回路のサイズに依存する)手数料である。Contract Fee は実行するオペコードの種類と数に依存して決定する。また、Base Fee と Contract Fee にかかる係数(Gas Price)の上限/下限は各ブロックの混雑具合に応じて決定する。 > Base Fee が EIP1559 における BaseFee と意味合いが違うことに注意してください。 ブロックの混雑具合に応じた係数の決定アルゴリズムに関しては EIP1559 を参考にする。 https://eips.ethereum.org/EIPS/eip-1559 ## NativeERC20s ガス代として扱える ERC20 を統括管理するコントラクト `NativeERC20s` を作成する。このコントラクトはプロトコルレベルで呼び出されるコントラクトであり、これを用いてその ERC20 がガス代として扱えるかまたガス代とするときに必要なトークンの量の計算を行う。 ガス代の計算には Oracle の存在が、ネイティブトークンの登録にはガバナンスの存在が不可欠である。 **また、Oracle が機能しなくなったとき(最新 n Block 以上価格が更新されなかったとき)強制的に depreacate される緊急避難装置があってもよい。** ```solidity= interface Governceable { modifier onlyGovernance() { ... } function governance() public retunrs(address); function transferGovernance(address newGovernance) public virtual onlyGovernance } interface Oracle { modifier onlyOracle() { ... } function oracle() public retunrs(address); function transferOracle(address newGovernance) public virtual onlyGovernance } contract NativeERC20s is Governanceable, Oracle { // default 0 map (address => uint256) _erc20sPerGas; set address _nativeErc20s; // Get the erc20's price per gas.(default 0 means not used unset the erc20.) function perGas(address contract erc20) public view returns (uint256) { if(_nativeErc20s.has(erc20)) return _erc20sPerGas[erc20]; return 0; } // Get the bool that is native erc20? function isNativeErc20(address contract erc20) public view returns (bool) { return _nativeErc20s.has(erc20); } function setPerGas(address contract erc20, uint256 perGas) public onlyOracle { _erc20sPerGas[erc20] = perGas; } function setNativeErc20(address contract erc20) public onlyGovernance { _nativeErc20s.insert(erc20); // set default value. _erc20sPerGas[erc20] = 0; } function depreacateNativeErc20(address contract erc20) public onlyGovernance { _nativeErc20s.remove(erc20); } } ``` ## Operator execution contract オペレータはユーザから受け取った TxPayload をもとに次のようなルートコントラクトを実行することになる。 ```solidity= contract RootExec { NativeErc20s _nativeErc20s; function exec(address operator, bytes[] tx...) public { tx.execution(); // root op code: get the current proof size. uint32 base_base = _COUNT_CURRENT_PROOF_SIZE; // root op code: get the current count of execution op code. uint32 contract_fee = _COUNT_CURRENT_EXEC_OP_CODE; address feeErc20 = tx.feeErc20(); uint256 perGas = _nativeErc20s.perGas(feeErc20); // calc fee uint256 calcFee = calcFee(base_fee, contract_fee, perGas); // msg.sender pay fee to operator. zERC20(feeErc).transferFrom(operator, calcFee); } } ``` ## オペレータが State Diff レシートに該当 ERC20 のマイナス残高を付け加えて送る。 上記の contract の実行結果について StateDiff を返す仕様にすることで万事解決。 Fee logic 追加前後で外から見たときのインターフェイスや通信プロトコルは変わらない。 ## Lightning-BTC 支払いについて <!-- Lightning-BTC でガス代を先払いしたこと zkProof する。ここで、ユーザがガス代を不正に払わずにトランザクションを実行できないことが保証される。**ガス代を受け取ったオペレータがトランザクションを実行しないことが可能なことに注意する。** $$C_{provePayementFee}((address, amount), invoice) \to \{true,false\}$$ $$zkProve((address, amount), invoice), C_{provePayementFee}) \to zkProof_{provePayementFee}$$ | name | type | remarks | | :--: | :--: | :--: | | paymentAmount | uint64 | payment amount | | invoice | address | lightning payment invoice | --> 提出する L2 transaction の onetimeAddress をオペレータに提出する。オペレータはその onetimeAddress に対応した invoice を渡す。その後、Lightning-BTC でガス代を先払いしたことの invoice を Tx と一緒に提出する。ここで、ユーザがガス代を不正に払わずにトランザクションを実行できないことが保証される。**ガス代を受け取ったオペレータがトランザクションを実行しないことが可能なことに注意する。** ```mermaid sequenceDiagram actor U as User participant O as Operator autonumber U ->> O : submit onetimeAddress O ->> U : invoice with onetimeAddress U ->> O : lightnig payment with the above invoice U ->> O : submitTx with invoice(lightning payment) O ->> O : Check fee payment O ->> O : verifyAndExec(tx) O ->> U : Response: stateDiff ``` ## 以下考察過程 ``` ### 先払い オペレータが手数料をもらったまま、トランザクションを処理しない可能性がある。 Trustless な手数料支払には、Lightning が L2 の Tx を監視する必要がある。 1. Lightning で btc-pay 2. lightning script?でL2の tx commit を確認 3. 2 が確認されたら operator に送金 4. 2 が一定時間確認されなかったら送金者に戻る ### 後払い ユーザがトランザクションを受け入れてもらった後、支払わない可能性がある。 Trustless な手数料支払には、L2 が Lightning の Tx を監視する必要がある。 1. Lightning で btc をL2引き落としscript に deposit 2. L2 で lightnig の deposit を確認し、tx を取り入れる。 3. 1 の script に tx を取り込んだことの証明を投げる。 - zkProof 5. btc が operator に送金される。 ### 問題点 Lightning payment をしたとき、Lighning wallet と L2 の tx が紐付かない? ligtning で特殊な送金ロジックを行うには結局 bitcoin script を使用する必要があり L1 を叩かなければいけないので、Trustless にやっていくのは難しい。 ## 備考 State diff update でオペレータから不正な state diff を返却されたときに詰んでしまわないか? -> あるトランザクションにおける state diff について、妥当かどうかの検証が必要。 プロトコル(オペレータ)が実行する特殊なコントラクトについて別名で読んだほうが良い?(今回で RootExec コントラクトのこと) ```