EIP-7702 是一项以太坊改进提案,旨在通过引入一种新的交易类型,使外部拥有账户(EOA)能够临时像智能合约账户一样运作。
这项提案的目的是简化账户抽象,允许普通的 Web3 钱包能够实现智能钱包的某些功能。
evm账户模型大概如下
address => {
Nonce uint64
Balance *uint256.Int
Code []byte
}
对于eoa账户,code里无代码,不具备合约功能
使用7702交易,eoa授权合约后, eoa账户下也会有code。跟eoa地址交互,是跟他的合约交互。
比如授权后,他的合约里没提供fallback方法,就无法收bnb
比如授权合约是一个工具类转出token,那其实每个人都可以调用他的方法转出token
授权合约/取消授权合约,都需要通过7702的交易类型;
7702交易类型,为新增的一个交易类型。
// SetCodeTx implements the EIP-7702 transaction type which temporarily installs
// the code at the signer's address.
type SetCodeTx struct {
ChainID *uint256.Int
Nonce uint64
GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas
GasFeeCap *uint256.Int // a.k.a. maxFeePerGas
Gas uint64
To common.Address
Value *uint256.Int
Data []byte
AccessList AccessList
AuthList []SetCodeAuthorization
// Signature values
V *uint256.Int
R *uint256.Int
S *uint256.Int
}
// SetCodeAuthorization is an authorization from an account to deploy code at its address.
type SetCodeAuthorization struct {
ChainID uint256.Int `json:"chainId" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"`
Nonce uint64 `json:"nonce" gencodec:"required"`
V uint8 `json:"yParity" gencodec:"required"`
R uint256.Int `json:"r" gencodec:"required"`
S uint256.Int `json:"s" gencodec:"required"`
}
用户授权,需要对合约地址和用户nonce, chainid进行签名即可。
在执行交易前,先查看SetCodeAuthorizations, 设置code到用户地址下,再进行执行交易;
啊这里要注意点,要是applyAuthorization有error,这里是忽略error的
if contractCreation {
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value)
} else {
// Increment the nonce for the next transaction.
st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall)
// Apply EIP-7702 authorizations.
if msg.SetCodeAuthorizations != nil {
for _, auth := range msg.SetCodeAuthorizations {
// Note errors are ignored, we simply skip invalid authorizations here.
st.applyAuthorization(&auth)
}
}
// Perform convenience warming of sender's delegation target. Although the
// sender is already warmed in Prepare(..), it's possible a delegation to
// the account was deployed during this transaction. To handle correctly,
// simply wait until the final state of delegations is determined before
// performing the resolution and warming.
if addr, ok := types.ParseDelegation(st.state.GetCode(*msg.To)); ok {
st.state.AddAddressToAccessList(addr)
}
// Execute the transaction's call.
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value)
}
查询某账户是否是有授权
//eth_getCode
返回值如果是 以 0xef010051510973ba7c1cc5a5e48e180c68b2ea4b9ec7df 0xef0100开头,那就是授权合约
合约地址就把前缀去掉就行
要取消,就签一笔address = common.Address{}的授权就行
如果是自己签授权/取消授权,因为evm 里msg.from nonce先生效,所以auth里的nonce记得要➕1
最后放一个例子
func TestCccD(t *testing.T) {
ctx := context.Background()
client, _ := ethclient.DialContext(ctx, "https://data-seed-prebsc-1-s1.bnbchain.org:8545")
feeKey, _ := crypto.HexToECDSA("")
feeAddress := crypto.PubkeyToAddress(feeKey.PublicKey)
authKey, _ := crypto.HexToECDSA("")
authAddress := crypto.PubkeyToAddress(authKey.PublicKey)
authNonce, err := client.NonceAt(context.Background(), authAddress, nil)
noErr(err)
feeNonce, err := client.NonceAt(context.Background(), feeAddress, nil)
noErr(err)
fmt.Println("fee", feeAddress.String(), feeNonce)
fmt.Println("auth", authAddress.String(), authNonce)
chainId := uint256.NewInt(97)
authList, err := types.SignSetCode(authKey, types.SetCodeAuthorization{
ChainID: *chainId,
//Address: common.HexToAddress("0x51510973ba7c1cc5a5e48e180c68b2ea4b9ec7df"),
Address: common.Address{},
Nonce: authNonce,
})
//fmt.Println(authList, err)
//authList.Address = common.HexToAddress("0x51510973ba8c1cc5a5e48e180c68b2ea4b9ec7df")
//authList.Nonce = 123
data, err := hex.DecodeString("79f2447e000000000000000000000000ec5dcb5dbf4b114c9d0f65bccab49ec54f6a0867000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeae6c472be3ced42094b0f5a4f49380d0cfbccc000000000000000000000000eeae6c472be3ced42094b0f5a4f49380d0cfbccc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012c")
noErr(err)
tx := &types.SetCodeTx{
ChainID: chainId,
Nonce: feeNonce,
GasTipCap: uint256.NewInt(1e9),
GasFeeCap: uint256.NewInt(1e9),
Gas: 1000000,
To: authAddress,
Value: nil,
Data: data,
AccessList: nil,
AuthList: []types.SetCodeAuthorization{authList},
}
//fmt.Println(authList)
//
signedTx, err := types.SignTx(types.NewTx(tx), types.NewPragueSigner(big.NewInt(97)), feeKey)
noErr(err)
fmt.Println(signedTx.Type())
//tx := &types.LegacyTx{
// Nonce: feeNonce,
// GasPrice: big.NewInt(1e9),
// Gas: 100000,
// To: &authAddress,
// Value: nil,
// Data: data,
//}
//signedTx, err := types.SignTx(types.NewTx(tx), types.NewEIP155Signer(big.NewInt(97)), feeKey)
//noErr(err)
fmt.Println(signedTx.Type())
err = client.SendTransaction(ctx, signedTx)
noErr(err)
fmt.Println(signedTx.Hash())
}
