以太坊交易通过 nonce
和 signauter
验证,只能通过外部账户(EOA) 发起交易。 zkSync 2.0 开始支持Abstract accout
,通过合约实现验证逻辑,即抽象账户使合约能够支付手续费,并发起交易执行。
抽象账户的使用情形包括:
- 智能合约钱包,例如多签;
- 手续费支持可以使用其它代币,并不局限于 ETH;
- 支持更多密码算法,除了ECDSA, 还可以支持Schnorr, BLS等;
- 在隐私方案中,不再需要
relayers
,主要针对 tornado.cash. - 协议中可以支持为用户支付手续费用。
采用抽象账户实现多签的简单示例:
// SPDX-License-Identifier: MPL-2.0
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2; // Enables structs in the ABI.
account contract TwoOfTwo { // Note the new `account` keyword!
// This marks the contract as
// accepting AA transactions, and
// makes solidity emit a special
// prelude. More on that later.
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
address public owner0; // Making calls from this account
address public owner1; // requires two signatures, making
// this a 2-of-2 multisig.
constructor(
address _owner0,
address _owner1
) payable {
owner0 = _owner0;
owner1 = _owner1;
}
function transfer( // Emulates a regular Ethereum
uint256 gasPrice, // transaction, but with a new
uint256 gasLimit, // validity requirement:
address payable to, //
uint256 amount, //
bytes calldata payload, //
Signature calldata sig0, // Two signatures instead of one!
Signature calldata sig1
) external {
bytes32 digest = keccak256( // The signature validation logic
abi.encodePacked( // for AA contracts is implemented
this, // in the contract itself. This
gasPrice, // gives contracts a ton of
gasLimit, // flexibility. You don't even need
to, // to use ECDSA signatures at all!
amount,
tx.nonce, // Newly exposed!
payload
)
);
address signer0 = // If either signature is invalid
recover(digest, sig0); // the contract reverts the
require(owner0 == signer0); // transaction.
address signer1 = // Since the revert happens before
recover(digest, sig1) // `paygas` is called, the entire
require(owner1 == signer1); // transaction is invalid, and
// this contract's balance is not
// reduced.
paygas(gasPrice, gasLimit); // Signals that the transaction is
// valid, and the gas price and
// limit the contract is willing to
// pay. Also creates a checkpoint:
// changes before `paygas` are not
// reverted if execution fails past
// this point.
(bool success,) =
to.call{value: amount}(payload);
require(success);
}
function recover(
bytes32 digest,
Signature calldata signature
) private pure returns (address) {
return ecrecover(
digest,
signature.v,
signature.r,
signature.s
);
}
}
参考
https://hackmd.io/@angelfish/BytzUTdCK
https://eips.ethereum.org/EIPS/eip-2938
网友评论