From 6680b836f6a65e5fd84d6d69309846aba3ceac80 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Tue, 4 Feb 2025 19:18:25 -0800 Subject: [PATCH] accounts/abi/bind/v2: modify v2 DeployContract to take packed input to be more in-line with the rest of the API. add a default DeployFn implementation for the deployer. --- accounts/abi/bind/old.go | 11 +++- accounts/abi/bind/v2/boundcontractv1.go | 19 ------ accounts/abi/bind/v2/lib.go | 22 ++++++- accounts/abi/bind/v2/lib_test.go | 82 +++++++++++++++---------- 4 files changed, 79 insertions(+), 55 deletions(-) diff --git a/accounts/abi/bind/old.go b/accounts/abi/bind/old.go index 016c1dd5d1..ed62a4ebd4 100644 --- a/accounts/abi/bind/old.go +++ b/accounts/abi/bind/old.go @@ -227,7 +227,16 @@ func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller } func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { - return bind2.DeployContract(opts, abi, bytecode, backend, params...) + packed, err := abi.Pack("", params...) + if err != nil { + return common.Address{}, nil, nil, err + } + addr, tx, err := bind2.DeployContract(opts, bytecode, backend, packed) + if err != nil { + return common.Address{}, nil, nil, err + } + boundContract := NewBoundContract(addr, abi, backend, backend, backend) + return addr, tx, boundContract, nil } // MetaData collects all metadata for a bound contract. diff --git a/accounts/abi/bind/v2/boundcontractv1.go b/accounts/abi/bind/v2/boundcontractv1.go index 565af66d21..c1fd3dd056 100644 --- a/accounts/abi/bind/v2/boundcontractv1.go +++ b/accounts/abi/bind/v2/boundcontractv1.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" ) @@ -37,24 +36,6 @@ func NewBoundContractV1(address common.Address, abi abi.ABI, caller ContractCall } } -// DeployContract deploys a contract onto the Ethereum blockchain and binds the -// deployment address with a Go wrapper. -func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...any) (common.Address, *types.Transaction, *BoundContractV1, error) { - // Otherwise try to deploy the contract - c := NewBoundContractV1(common.Address{}, abi, backend, backend, backend) - - input, err := c.abi.Pack("", params...) - if err != nil { - return common.Address{}, nil, nil, err - } - tx, err := c.transact(opts, nil, append(bytecode, input...)) - if err != nil { - return common.Address{}, nil, nil, err - } - c.address = crypto.CreateAddress(opts.From, tx.Nonce()) - return c.address, tx, c, nil -} - // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named diff --git a/accounts/abi/bind/v2/lib.go b/accounts/abi/bind/v2/lib.go index fc4362e2c0..881b8b3b33 100644 --- a/accounts/abi/bind/v2/lib.go +++ b/accounts/abi/bind/v2/lib.go @@ -17,6 +17,7 @@ package bind import ( + "context" "errors" "github.com/ethereum/go-ethereum" @@ -180,10 +181,10 @@ func Transact(c BoundContract, opt *TransactOpts, packedInput []byte) (*types.Tr return c.transact(opt, &addr, packedInput) } -// DeployContractRaw deploys a contract onto the Ethereum blockchain and binds the +// DeployContract deploys a contract onto the Ethereum blockchain and binds the // deployment address with a Go wrapper. It expects its parameters to be abi-encoded // bytes. -func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, error) { +func DeployContract(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, error) { c := NewBoundContractV1(common.Address{}, abi.ABI{}, backend, backend, backend) tx, err := c.RawCreationTransact(opts, append(bytecode, packedParams...)) if err != nil { @@ -192,3 +193,20 @@ func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBack address := crypto.CreateAddress(opts.From, tx.Nonce()) return address, tx, nil } + +// DefaultDeployer returns a DeployFn that signs and submits creation transactions using the given signer. +func DefaultDeployer(ctx context.Context, from common.Address, backend ContractBackend, signer SignerFn) DeployFn { + opts := &TransactOpts{ + From: from, + Nonce: nil, + Signer: signer, + Context: ctx, + } + return func(input []byte, deployer []byte) (common.Address, *types.Transaction, error) { + addr, tx, err := DeployContract(opts, deployer, backend, input) + if err != nil { + return common.Address{}, nil, err + } + return addr, tx, nil + } +} diff --git a/accounts/abi/bind/v2/lib_test.go b/accounts/abi/bind/v2/lib_test.go index 78d6fed55c..51d9dd811a 100644 --- a/accounts/abi/bind/v2/lib_test.go +++ b/accounts/abi/bind/v2/lib_test.go @@ -41,6 +41,7 @@ import ( ) var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") +var testAddr = crypto.PubkeyToAddress(testKey.PublicKey) // JSON returns a parsed ABI interface and error if it failed. func JSON(reader io.Reader) (abi.ABI, error) { @@ -53,8 +54,7 @@ func JSON(reader io.Reader) (abi.ABI, error) { return instance, nil } -func testSetup() (*bind.TransactOpts, *backends.SimulatedBackend, error) { - testAddr := crypto.PubkeyToAddress(testKey.PublicKey) +func testSetup() (*backends.SimulatedBackend, error) { backend := simulated.NewBackend( types.GenesisAlloc{ testAddr: {Balance: big.NewInt(10000000000000000)}, @@ -64,23 +64,6 @@ func testSetup() (*bind.TransactOpts, *backends.SimulatedBackend, error) { }, ) - signer := types.LatestSigner(params.AllDevChainProtocolChanges) - opts := &bind.TransactOpts{ - From: testAddr, - Nonce: nil, - Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { - signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) - if err != nil { - return nil, err - } - signedTx, err := tx.WithSignature(signer, signature) - if err != nil { - return nil, err - } - return signedTx, nil - }, - Context: context.Background(), - } // we should just be able to use the backend directly, instead of using // this deprecated interface. However, the simulated backend no longer // implements backends.SimulatedBackend... @@ -88,19 +71,30 @@ func testSetup() (*bind.TransactOpts, *backends.SimulatedBackend, error) { Backend: backend, Client: backend.Client(), } - return opts, &bindBackend, nil + return &bindBackend, nil } -func makeTestDeployer(auth *bind.TransactOpts, backend bind.ContractBackend) func(input, deployer []byte) (common.Address, *types.Transaction, error) { - return func(input, deployer []byte) (common.Address, *types.Transaction, error) { - return bind.DeployContractRaw(auth, deployer, backend, input) +func makeTestDeployer(backend bind.ContractBackend) func(input, deployer []byte) (common.Address, *types.Transaction, error) { + signer := types.LatestSigner(params.AllDevChainProtocolChanges) + sign := func(sender common.Address, tx *types.Transaction) (*types.Transaction, error) { + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) + if err != nil { + return nil, err + } + signedTx, err := tx.WithSignature(signer, signature) + if err != nil { + return nil, err + } + return signedTx, nil } + + return bind.DefaultDeployer(context.Background(), testAddr, backend, sign) } // test that deploying a contract with library dependencies works, // verifying by calling method on the deployed contract. func TestDeploymentLibraries(t *testing.T) { - opts, bindBackend, err := testSetup() + bindBackend, err := testSetup() if err != nil { t.Fatalf("err setting up test: %v", err) } @@ -112,7 +106,7 @@ func TestDeploymentLibraries(t *testing.T) { Contracts: []*bind.MetaData{&nested_libraries.C1MetaData}, Inputs: map[string][]byte{nested_libraries.C1MetaData.ID: constructorInput}, } - res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend)) + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(bindBackend)) if err != nil { t.Fatalf("err: %+v\n", err) } @@ -144,7 +138,7 @@ func TestDeploymentLibraries(t *testing.T) { // Same as TestDeployment. However, stagger the deployments with overrides: // first deploy the library deps and then the contract. func TestDeploymentWithOverrides(t *testing.T) { - opts, bindBackend, err := testSetup() + bindBackend, err := testSetup() if err != nil { t.Fatalf("err setting up test: %v", err) } @@ -154,7 +148,7 @@ func TestDeploymentWithOverrides(t *testing.T) { deploymentParams := &bind.DeploymentParams{ Contracts: nested_libraries.C1MetaData.Deps, } - res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend)) + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(bindBackend)) if err != nil { t.Fatalf("err: %+v\n", err) } @@ -180,7 +174,7 @@ func TestDeploymentWithOverrides(t *testing.T) { Inputs: map[string][]byte{nested_libraries.C1MetaData.ID: constructorInput}, Overrides: overrides, } - res, err = bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend)) + res, err = bind.LinkAndDeploy(deploymentParams, makeTestDeployer(bindBackend)) if err != nil { t.Fatalf("err: %+v\n", err) } @@ -209,15 +203,37 @@ func TestDeploymentWithOverrides(t *testing.T) { } } +// returns transaction auth to send a basic transaction from testAddr +func defaultTxAuth() *bind.TransactOpts { + signer := types.LatestSigner(params.AllDevChainProtocolChanges) + opts := &bind.TransactOpts{ + From: testAddr, + Nonce: nil, + Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) + if err != nil { + return nil, err + } + signedTx, err := tx.WithSignature(signer, signature) + if err != nil { + return nil, err + } + return signedTx, nil + }, + Context: context.Background(), + } + return opts +} + func TestEvents(t *testing.T) { // test watch/filter logs method on a contract that emits various kinds of events (struct-containing, etc.) - txAuth, backend, err := testSetup() + backend, err := testSetup() if err != nil { t.Fatalf("error setting up testing env: %v", err) } deploymentParams := &bind.DeploymentParams{Contracts: []*bind.MetaData{&events.CMetaData}} - res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(txAuth, backend)) + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(backend)) if err != nil { t.Fatalf("error deploying contract for testing: %v", err) } @@ -245,7 +261,7 @@ func TestEvents(t *testing.T) { defer sub2.Unsubscribe() packedInput := c.PackEmitMulti() - tx, err := bind.Transact(instance, txAuth, packedInput) + tx, err := bind.Transact(instance, defaultTxAuth(), packedInput) if err != nil { t.Fatalf("failed to send transaction: %v", err) } @@ -310,13 +326,13 @@ done: func TestErrors(t *testing.T) { // test watch/filter logs method on a contract that emits various kinds of events (struct-containing, etc.) - txAuth, backend, err := testSetup() + backend, err := testSetup() if err != nil { t.Fatalf("error setting up testing env: %v", err) } deploymentParams := &bind.DeploymentParams{Contracts: []*bind.MetaData{&solc_errors.CMetaData}} - res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(txAuth, backend)) + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(backend)) if err != nil { t.Fatalf("error deploying contract for testing: %v", err) }