Skip to content

Commit

Permalink
implement erc20 deposit state transition logic
Browse files Browse the repository at this point in the history
  • Loading branch information
noot committed May 23, 2024
1 parent 27d7b77 commit b4ed58b
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 24 deletions.
31 changes: 26 additions & 5 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,12 @@ func (result *ExecutionResult) Revert() []byte {
}

// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) {
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool, isDepositTx bool) (uint64, error) {
if isDepositTx {
// deposit txs are gasless
return 0, nil
}

// Set the starting gas for the raw transaction
var gas uint64
if isContractCreation && isHomestead {
Expand Down Expand Up @@ -274,6 +279,12 @@ func (st *StateTransition) buyGas() error {
}

func (st *StateTransition) preCheck() error {
if st.msg.IsDepositTx {
// deposit txs do not require checks as they are part of rollup consensus,
// not txs that originate externally.
return nil
}

// Only check transactions that are not fake
msg := st.msg
if !msg.SkipAccountChecks {
Expand Down Expand Up @@ -362,9 +373,9 @@ func (st *StateTransition) preCheck() error {
// However if any consensus issue encountered, return the error directly with
// nil evm execution result.
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// if this is a deposit tx, we only need to mint funds and no gas is used.
if st.msg.IsDepositTx {
st.state.AddBalance(st.msg.From, st.msg.Value)
// if this is a native asset deposit tx, we only need to mint funds.
if st.msg.IsDepositTx && len(st.msg.Data) == 0 {
st.state.AddBalance(*st.msg.To, st.msg.Value)
return &ExecutionResult{
UsedGas: 0,
Err: nil,
Expand Down Expand Up @@ -402,7 +413,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
)

// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai, msg.IsDepositTx)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -438,6 +449,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
}

// if this is a deposit tx, don't refund gas and also don't pay to the coinbase,
// as no gas was used.
if st.msg.IsDepositTx {
return &ExecutionResult{
UsedGas: st.gasUsed(),
Err: vmerr,
ReturnData: ret,
}, nil
}

if !rules.IsLondon {
// Before EIP-3529: refunds were capped to gasUsed / 2
st.refundGas(params.RefundQuotient)
Expand Down
2 changes: 1 addition & 1 deletion core/txpool/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
}
// Ensure the transaction has more gas than the bare minimum needed to cover
// the transaction metadata
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time))
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time), false)
if err != nil {
return err
}
Expand Down
13 changes: 8 additions & 5 deletions core/types/deposit_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ import (
var _ TxData = &DepositTx{}

type DepositTx struct {
// the address of the account that initiated the deposit
// the bridge sender address set in the genesis file
// ie. the minter or the caller of the ERC20 contract
From common.Address
// value to be minted to `From`
// value to be minted to the recipient, if this is a native asset mint
Value *big.Int
// gas limit
Gas uint64

// if this is an ERC20 mint, the following fields are set
To *common.Address
// if this is a native asset mint, this is set to the mint recipient
// if this is an ERC20 mint, this is set to the ERC20 contract address
To *common.Address
// if this is an ERC20 mint, the following field is set
// to the `mint` function calldata.
Data []byte
}

Expand Down
23 changes: 11 additions & 12 deletions grpc/execution/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func NewExecutionServiceServerV1Alpha2(eth *eth.Ethereum) (*ExecutionServiceServ
bc: bc,
bridgeAddresses: bridgeAddresses,
bridgeAllowedAssetIDs: bridgeAllowedAssetIDs,
bridgeSenderAddress: bc.Config().AstriaBridgeSenderAddress,
bridgeSenderAddress: bc.Config().AstriaBridgeSenderAddress,
nextFeeRecipient: nextFeeRecipient,
}, nil
}
Expand Down Expand Up @@ -269,6 +269,9 @@ func (s *ExecutionServiceServerV1Alpha2) ExecuteBlock(ctx context.Context, req *
continue
}

recipient := common.HexToAddress(deposit.DestinationChainAddress)
amount := bac.ScaledDepositAmount(protoU128ToBigInt(deposit.Amount))

if bac.Erc20Asset != nil {
log.Debug("creating deposit tx to mint ERC20 asset", "token", bac.AssetDenom, "erc20Address", bac.Erc20Asset.ContractAddress)
abi, err := contracts.AstriaMintableERC20MetaData.GetAbi()
Expand All @@ -277,20 +280,17 @@ func (s *ExecutionServiceServerV1Alpha2) ExecuteBlock(ctx context.Context, req *
return nil, fmt.Errorf("failed to get abi for erc20 contract for asset %s: %w", bac.AssetDenom, err)
}

recipient := common.HexToAddress(deposit.DestinationChainAddress)
amount := protoU128ToBigInt(deposit.Amount)

// pack arguments for calling the `mint` function on the ERC20 contract
args := []interface{}{recipient, bac.ScaledDepositAmount(amount)}
args := []interface{}{recipient, amount}
calldata, err := abi.Pack("mint", args...)
if err != nil {
return nil, err
}

txdata := types.DepositTx{
From: common.Address{}, // don't need to set this
Value: new(big.Int), // don't need to set this
Gas: 0,
From: s.bridgeSenderAddress,
Value: new(big.Int), // don't need to set this
Gas: 0, // TODO: ensure this is gasless
To: &bac.Erc20Asset.ContractAddress,
Data: calldata,
}
Expand All @@ -300,11 +300,10 @@ func (s *ExecutionServiceServerV1Alpha2) ExecuteBlock(ctx context.Context, req *
continue
}

amount := protoU128ToBigInt(deposit.Amount)
recipient := common.HexToAddress(deposit.DestinationChainAddress)
txdata := types.DepositTx{
From: recipient,
Value: bac.ScaledDepositAmount(amount),
From: s.bridgeSenderAddress,
To: &recipient,
Value: amount,
Gas: 0,
}

Expand Down
2 changes: 1 addition & 1 deletion light/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
}

// Should supply enough intrinsic gas
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai)
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai, false)
if err != nil {
return err
}
Expand Down

0 comments on commit b4ed58b

Please sign in to comment.