Commit 9d13ae01 authored by Wyatt Barnes's avatar Wyatt Barnes Committed by GitHub

Refactor BindGen E2E tests (#8741)

parent 6c23fbee
...@@ -524,16 +524,16 @@ jobs: ...@@ -524,16 +524,16 @@ jobs:
working_directory: op-bindings working_directory: op-bindings
- notify-failures-on-develop - notify-failures-on-develop
bindgen-test: bindgen-test-e2e:
docker: docker:
- image: <<pipeline.parameters.ci_builder_image>> - image: <<pipeline.parameters.ci_builder_image>>
resource_class: xlarge resource_class: xlarge
steps: steps:
- checkout - checkout
- run: - run:
name: bindgen test name: bindgen test E2E
command: make test-bindgen-e2e command: make test-bindgen-e2e
working_directory: op-bindings working_directory: op-bindings-e2e
- notify-failures-on-develop - notify-failures-on-develop
js-lint-test: js-lint-test:
...@@ -2012,7 +2012,7 @@ workflows: ...@@ -2012,7 +2012,7 @@ workflows:
context: context:
- slack - slack
- oplabs-etherscan - oplabs-etherscan
- bindgen-test: - bindgen-test-e2e:
context: context:
- slack - slack
- oplabs-etherscan - oplabs-etherscan
test-bindgen-e2e:
go test ./... -count=1
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
package bindgen
import (
"github.com/ethereum-optimism/optimism/op-bindings/bindgen"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
)
var fetchContractDataTests = []struct {
name string
contractVerified bool
chain string
deploymentAddress string
expectedContractData bindgen.ContractData
}{
{
"MultiCall3 on ETH",
true,
"eth",
"0xcA11bde05977b3631167028862bE2a173976CA11",
bindgen.ContractData{
Abi: MultiCall3Abi,
DeployedBin: MultiCall3DeployedBytecode,
DeploymentTx: etherscan.Transaction{
Input: MultiCall3InitBytecode,
Hash: "0x00d9fcb7848f6f6b0aae4fb709c133d69262b902156c85a473ef23faa60760bd",
To: "",
},
},
},
{
"MultiCall3 on OP",
true,
"op",
"0xcA11bde05977b3631167028862bE2a173976CA11",
bindgen.ContractData{
Abi: MultiCall3Abi,
DeployedBin: MultiCall3DeployedBytecode,
DeploymentTx: etherscan.Transaction{
Input: MultiCall3InitBytecode,
Hash: "0xb62f9191a2cf399c0d2afd33f5b8baf7c6b52af6dd2386e44121b1bab91b80e5",
To: "",
},
},
},
{
"SafeSingletonFactory on ETH",
false,
"eth",
"0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7",
bindgen.ContractData{
Abi: "",
DeployedBin: SafeSingletonFactoryDeployedBytecode,
DeploymentTx: etherscan.Transaction{
Input: SafeSingletonFactoryInitBytecode,
Hash: "0x69c275b5304db980105b7a6d731f9e1157a3fe29e7ff6ff95235297df53e9928",
To: "",
},
},
},
{
"Permit2 on ETH",
true,
"eth",
"0x000000000022D473030F116dDEE9F6B43aC78BA3",
bindgen.ContractData{
Abi: Permit2Abi,
DeployedBin: Permit2DeployedBytecode,
DeploymentTx: etherscan.Transaction{
Input: Permit2InitBytecode,
Hash: "0xf2f1fe96c16ee674bb7fcee166be52465a418927d124f5f1d231b36eae65d377",
To: "0x4e59b44847b379578588920ca78fbf26c0b4956c",
},
},
},
}
// Not currently being tested due to complexity of test setup:
// - FetchDeploymentTxHash failure
// Not being tested because the contract would need to have deployed bytecode to
// pass FetchDeployedBytecode, which means Etherscan should have indexed the deployment tx
// - FetchDeploymentTx failure
// Not being tested for the same reason and there would be no way to pass FetchDeploymentTxHash,
// but not be able to retrieve tx details
var fetchContractDataTestsFailures = []struct {
name string
contractVerified bool
chain string
deploymentAddress string
expectedError string
}{
{
"MultiCall3 on Foo",
true,
"foo",
"0xcA11bde05977b3631167028862bE2a173976CA11",
"unknown chain, unable to retrieve a contract data client for chain: foo",
},
{
// This test case is covering fetching an ABI for a non-verified contract that's we're saying is verified
"SafeSingletonFactory on ETH",
true,
"eth",
"0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7",
"error fetching ABI: operation failed permanently after 3 attempts: there was an issue with the Etherscan request",
},
{
// This test case is covering fetching the deployed bytecode for a non-existent contract
"Nonexistent on ETH",
false,
"eth",
"0x914d7Fec6aaC8cd542e72Bca78B30650d455555",
"error fetching deployed bytecode: API response result is not expected bytecode string",
},
}
var compareInitBytecodeWithOpTests = []struct {
name string
contractMetadataEth bindgen.RemoteContractMetadata
initCodeShouldMatch bool
}{
{
name: "Safe_v130 Init Bytecode Should Match",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecodeNoSalt,
DeployedBin: "",
},
initCodeShouldMatch: true,
},
{
name: "Safe_v130 Compare Init Bytecode Only On OP",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecodeNoSalt,
DeployedBin: "",
},
initCodeShouldMatch: true,
},
{
name: "Create2Deployer's Init Bytecode Should Not Match",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Create2Deployer",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"),
Eth: common.HexToAddress("0xF49600926c7109BD66Ab97a2c036bf696e58Dbc2"),
},
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Create2DeployerInitBytecode,
DeployedBin: Create2DeployerDeployedBytecode,
},
initCodeShouldMatch: false,
},
}
var compareInitBytecodeWithOpTestsFailures = []struct {
name string
contractMetadataEth bindgen.RemoteContractMetadata
initCodeShouldMatch bool
expectedError string
}{
{
name: "Safe_v130 Mismatch Init Bytecode",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Permit2InitBytecodeNoSalt,
DeployedBin: "",
},
initCodeShouldMatch: true,
expectedError: "expected initialization bytecode to match on Ethereum and Optimism, but it doesn't.",
},
{
name: "Safe_v130 No Deployment on Optimism",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecode,
DeployedBin: Safe_v130DeployedBytecode,
},
initCodeShouldMatch: true,
expectedError: "no deployment address on Optimism provided for Safe_v130",
},
{
name: "MultiCall3 Expected Init Code Not to Match, but it Does",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "MultiCall3",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11"),
Eth: common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11"),
},
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: MultiCall3InitBytecode,
DeployedBin: MultiCall3DeployedBytecode,
},
initCodeShouldMatch: false,
expectedError: "expected initialization bytecode on Ethereum to not match on Optimism, but it did.",
},
{
name: "Safe_v130 No Init Bytecode Provided",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
initCodeShouldMatch: false,
expectedError: "no initialization bytecode provided for ETH deployment for comparison",
},
}
var compareDeployedBytecodeWithOpTests = []struct {
name string
contractMetadataEth bindgen.RemoteContractMetadata
deployedCodeShouldMatch bool
}{
{
name: "Safe_v130 Deployed Bytecode Should Match",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
deployedCodeShouldMatch: true,
},
{
name: "Safe_v130 Compare Deployed Bytecode Only On OP",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecodeNoSalt,
DeployedBin: Safe_v130DeployedBytecode,
},
deployedCodeShouldMatch: true,
},
{
name: "Permit2's Deployed Bytecode Should Not Match",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Permit2",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0x000000000022D473030F116dDEE9F6B43aC78BA3"),
Eth: common.HexToAddress("0x000000000022D473030F116dDEE9F6B43aC78BA3"),
},
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Permit2InitBytecode,
DeployedBin: Permit2DeployedBytecode,
},
deployedCodeShouldMatch: false,
},
}
var compareDeployedBytecodeWithOpTestsFailures = []struct {
name string
contractMetadataEth bindgen.RemoteContractMetadata
deployedCodeShouldMatch bool
expectedError string
}{
{
name: "Safe_v130 Mismatch Deplolyed Bytecode",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Permit2DeployedBytecode,
},
deployedCodeShouldMatch: true,
expectedError: "expected deployed bytecode to match on Ethereum and Optimism, but it doesn't.",
},
{
name: "Safe_v130 No Deployment on Optimism",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Permit2DeployedBytecode,
},
deployedCodeShouldMatch: true,
expectedError: "no deployment address on Optimism provided for Safe_v130",
},
{
name: "Safe_v130 Expected Deployed Code Not to Match, but it Does",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecode,
DeployedBin: Safe_v130DeployedBytecode,
},
deployedCodeShouldMatch: false,
expectedError: "expected deployed bytecode on Ethereum to not match on Optimism, but it does.",
},
{
name: "Safe_v130 No Deployed Bytecode Provided",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecode,
DeployedBin: "",
},
deployedCodeShouldMatch: false,
expectedError: "no deployed bytecode provided for ETH deployment for comparison",
},
}
var compareDeployedBytecodeWithRpcTests = []struct {
name string
contractMetadataEth bindgen.RemoteContractMetadata
chain string
}{
{
name: "Safe_v130 Compare Against ETH",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.Address{},
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
chain: "eth",
},
{
name: "Safe_v130 Compare Against OP",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.Address{},
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
chain: "op",
},
}
var compareDeployedBytecodeWithRpcTestsFailures = []struct {
name string
contractMetadataEth bindgen.RemoteContractMetadata
chain string
expectedError string
}{
{
name: "Safe_v130 Compare Against foo",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.Address{},
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: "",
},
chain: "foo",
expectedError: "unknown chain: foo, unable to retrieve a RPC client",
},
{
name: "Safe_v130 Bytecode Mismatch",
contractMetadataEth: bindgen.RemoteContractMetadata{
RemoteContract: bindgen.RemoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: bindgen.Deployments{
Op: common.Address{},
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Permit2DeployedBytecode,
},
chain: "eth",
expectedError: "Safe_v130 deployment bytecode from RPC doesn't match bytecode from Etherscan.",
},
}
package bindgen
import (
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindgen"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/ethclient"
)
var generator bindgen.BindGenGeneratorRemote = bindgen.BindGenGeneratorRemote{}
func configureGenerator(t *testing.T) error {
generator.ContractDataClients.Eth = etherscan.NewEthereumClient(os.Getenv("ETHERSCAN_APIKEY_ETH"))
generator.ContractDataClients.Op = etherscan.NewOptimismClient(os.Getenv("ETHERSCAN_APIKEY_OP"))
var err error
if generator.RpcClients.Eth, err = ethclient.Dial(os.Getenv("RPC_URL_ETH")); err != nil {
return fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.RpcClients.Op, err = ethclient.Dial(os.Getenv("RPC_URL_OP")); err != nil {
return fmt.Errorf("error initializing Optimism client: %w", err)
}
return nil
}
func TestFetchContractData(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTests {
t.Run(tt.name, func(t *testing.T) {
contractData, err := generator.FetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(contractData, tt.expectedContractData) {
t.Errorf("Retrieved contract data doesn't match expected. Expected: %s Retrieved: %s", tt.expectedContractData, contractData)
}
})
}
}
func TestFetchContractDataFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTestsFailures {
t.Run(tt.name, func(t *testing.T) {
_, err := generator.FetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareInitBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareInitBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithRpc(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithRpcFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
...@@ -28,7 +28,7 @@ bindings-build: bindgen-generate-local ...@@ -28,7 +28,7 @@ bindings-build: bindgen-generate-local
bindgen: compile bindgen-generate-all bindgen: compile bindgen-generate-all
bindgen-generate-all: bindgen-generate-all:
go run ./bindgen/ \ go run ./cmd/ \
generate \ generate \
--metadata-out ./$(pkg) \ --metadata-out ./$(pkg) \
--bindings-package $(pkg) \ --bindings-package $(pkg) \
...@@ -45,7 +45,7 @@ bindgen-generate-all: ...@@ -45,7 +45,7 @@ bindgen-generate-all:
bindgen-local: compile bindgen-generate-local bindgen-local: compile bindgen-generate-local
bindgen-generate-local: bindgen-generate-local:
go run ./bindgen/ \ go run ./cmd/ \
generate \ generate \
--metadata-out ./$(pkg) \ --metadata-out ./$(pkg) \
--bindings-package $(pkg) \ --bindings-package $(pkg) \
...@@ -56,7 +56,7 @@ bindgen-generate-local: ...@@ -56,7 +56,7 @@ bindgen-generate-local:
--forge-artifacts $(contracts-dir)/forge-artifacts --forge-artifacts $(contracts-dir)/forge-artifacts
bindgen-remote: bindgen-remote:
go run ./bindgen/ \ go run ./cmd/ \
generate \ generate \
--metadata-out ./$(pkg) \ --metadata-out ./$(pkg) \
--bindings-package $(pkg) \ --bindings-package $(pkg) \
...@@ -80,6 +80,3 @@ clean: ...@@ -80,6 +80,3 @@ clean:
test: test:
go test ./... go test ./...
test-bindgen-e2e:
RUN_E2E=true go test -count=1 ./bindgen/...
This source diff could not be displayed because it is too large. You can view the blob instead.
package main package bindgen
import (
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
)
var fetchContractDataTests = []struct {
name string
contractVerified bool
chain string
deploymentAddress string
expectedContractData contractData
}{
{
"MultiCall3 on ETH",
true,
"eth",
"0xcA11bde05977b3631167028862bE2a173976CA11",
contractData{
MultiCall3Abi,
MultiCall3DeployedBytecode,
etherscan.Transaction{
Input: MultiCall3InitBytecode,
Hash: "0x00d9fcb7848f6f6b0aae4fb709c133d69262b902156c85a473ef23faa60760bd",
To: "",
},
},
},
{
"MultiCall3 on OP",
true,
"op",
"0xcA11bde05977b3631167028862bE2a173976CA11",
contractData{
MultiCall3Abi,
MultiCall3DeployedBytecode,
etherscan.Transaction{
Input: MultiCall3InitBytecode,
Hash: "0xb62f9191a2cf399c0d2afd33f5b8baf7c6b52af6dd2386e44121b1bab91b80e5",
To: "",
},
},
},
{
"SafeSingletonFactory on ETH",
false,
"eth",
"0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7",
contractData{
"",
SafeSingletonFactoryDeployedBytecode,
etherscan.Transaction{
Input: SafeSingletonFactoryInitBytecode,
Hash: "0x69c275b5304db980105b7a6d731f9e1157a3fe29e7ff6ff95235297df53e9928",
To: "",
},
},
},
{
"Permit2 on ETH",
true,
"eth",
"0x000000000022D473030F116dDEE9F6B43aC78BA3",
contractData{
Permit2Abi,
Permit2DeployedBytecode,
etherscan.Transaction{
Input: Permit2InitBytecode,
Hash: "0xf2f1fe96c16ee674bb7fcee166be52465a418927d124f5f1d231b36eae65d377",
To: "0x4e59b44847b379578588920ca78fbf26c0b4956c",
},
},
},
}
// Not currently being tested due to complexity of test setup:
// - FetchDeploymentTxHash failure
// Not being tested because the contract would need to have deployed bytecode to
// pass FetchDeployedBytecode, which means Etherscan should have indexed the deployment tx
// - FetchDeploymentTx failure
// Not being tested for the same reason and there would be no way to pass FetchDeploymentTxHash,
// but not be able to retrieve tx details
var fetchContractDataTestsFailures = []struct {
name string
contractVerified bool
chain string
deploymentAddress string
expectedError string
}{
{
"MultiCall3 on Foo",
true,
"foo",
"0xcA11bde05977b3631167028862bE2a173976CA11",
"unknown chain, unable to retrieve a contract data client for chain: foo",
},
{
// This test case is covering fetching an ABI for a non-verified contract that's we're saying is verified
"SafeSingletonFactory on ETH",
true,
"eth",
"0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7",
"error fetching ABI: operation failed permanently after 3 attempts: there was an issue with the Etherscan request",
},
{
// This test case is covering fetching the deployed bytecode for a non-existent contract
"Nonexistent on ETH",
false,
"eth",
"0x914d7Fec6aaC8cd542e72Bca78B30650d455555",
"error fetching deployed bytecode: API response result is not expected bytecode string",
},
}
// The Init bytecode used for these tests can either be sourced // The Init bytecode used for these tests can either be sourced
// on-chain using the deployment tx of these contracts, or can be // on-chain using the deployment tx of these contracts, or can be
...@@ -161,429 +48,3 @@ var removeDeploymentSaltTestsFailures = []struct { ...@@ -161,429 +48,3 @@ var removeDeploymentSaltTestsFailures = []struct {
"expected salt: 4567 to be at the beginning of the contract initialization code: 0x1234abc, but it wasn't", "expected salt: 4567 to be at the beginning of the contract initialization code: 0x1234abc, but it wasn't",
}, },
} }
var compareInitBytecodeWithOpTests = []struct {
name string
contractMetadataEth remoteContractMetadata
initCodeShouldMatch bool
}{
{
name: "Safe_v130 Init Bytecode Should Match",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecodeNoSalt,
DeployedBin: "",
},
initCodeShouldMatch: true,
},
{
name: "Safe_v130 Compare Init Bytecode Only On OP",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecodeNoSalt,
DeployedBin: "",
},
initCodeShouldMatch: true,
},
{
name: "Create2Deployer's Init Bytecode Should Not Match",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Create2Deployer",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"),
Eth: common.HexToAddress("0xF49600926c7109BD66Ab97a2c036bf696e58Dbc2"),
},
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Create2DeployerInitBytecode,
DeployedBin: Create2DeployerDeployedBytecode,
},
initCodeShouldMatch: false,
},
}
var compareInitBytecodeWithOpTestsFailures = []struct {
name string
contractMetadataEth remoteContractMetadata
initCodeShouldMatch bool
expectedError string
}{
{
name: "Safe_v130 Mismatch Init Bytecode",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Permit2InitBytecodeNoSalt,
DeployedBin: "",
},
initCodeShouldMatch: true,
expectedError: "expected initialization bytecode to match on Ethereum and Optimism, but it doesn't.",
},
{
name: "Safe_v130 No Deployment on Optimism",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecode,
DeployedBin: Safe_v130DeployedBytecode,
},
initCodeShouldMatch: true,
expectedError: "no deployment address on Optimism provided for Safe_v130",
},
{
name: "MultiCall3 Expected Init Code Not to Match, but it Does",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "MultiCall3",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11"),
Eth: common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11"),
},
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: MultiCall3InitBytecode,
DeployedBin: MultiCall3DeployedBytecode,
},
initCodeShouldMatch: false,
expectedError: "expected initialization bytecode on Ethereum to not match on Optimism, but it did.",
},
{
name: "Safe_v130 No Init Bytecode Provided",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
initCodeShouldMatch: false,
expectedError: "no initialization bytecode provided for ETH deployment for comparison",
},
}
var compareDeployedBytecodeWithOpTests = []struct {
name string
contractMetadataEth remoteContractMetadata
deployedCodeShouldMatch bool
}{
{
name: "Safe_v130 Deployed Bytecode Should Match",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
deployedCodeShouldMatch: true,
},
{
name: "Safe_v130 Compare Deployed Bytecode Only On OP",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecodeNoSalt,
DeployedBin: Safe_v130DeployedBytecode,
},
deployedCodeShouldMatch: true,
},
{
name: "Permit2's Deployed Bytecode Should Not Match",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Permit2",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0x000000000022D473030F116dDEE9F6B43aC78BA3"),
Eth: common.HexToAddress("0x000000000022D473030F116dDEE9F6B43aC78BA3"),
},
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Permit2InitBytecode,
DeployedBin: Permit2DeployedBytecode,
},
deployedCodeShouldMatch: false,
},
}
var compareDeployedBytecodeWithOpTestsFailures = []struct {
name string
contractMetadataEth remoteContractMetadata
deployedCodeShouldMatch bool
expectedError string
}{
{
name: "Safe_v130 Mismatch Deplolyed Bytecode",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Permit2DeployedBytecode,
},
deployedCodeShouldMatch: true,
expectedError: "expected deployed bytecode to match on Ethereum and Optimism, but it doesn't.",
},
{
name: "Safe_v130 No Deployment on Optimism",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Permit2DeployedBytecode,
},
deployedCodeShouldMatch: true,
expectedError: "no deployment address on Optimism provided for Safe_v130",
},
{
name: "Safe_v130 Expected Deployed Code Not to Match, but it Does",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecode,
DeployedBin: Safe_v130DeployedBytecode,
},
deployedCodeShouldMatch: false,
expectedError: "expected deployed bytecode on Ethereum to not match on Optimism, but it does.",
},
{
name: "Safe_v130 No Deployed Bytecode Provided",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: Safe_v130InitBytecode,
DeployedBin: "",
},
deployedCodeShouldMatch: false,
expectedError: "no deployed bytecode provided for ETH deployment for comparison",
},
}
var compareDeployedBytecodeWithRpcTests = []struct {
name string
contractMetadataEth remoteContractMetadata
chain string
}{
{
name: "Safe_v130 Compare Against ETH",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.Address{},
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
chain: "eth",
},
{
name: "Safe_v130 Compare Against OP",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.HexToAddress("0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"),
Eth: common.Address{},
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Safe_v130DeployedBytecode,
},
chain: "op",
},
}
var compareDeployedBytecodeWithRpcTestsFailures = []struct {
name string
contractMetadataEth remoteContractMetadata
chain string
expectedError string
}{
{
name: "Safe_v130 Compare Against foo",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.Address{},
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: "",
},
chain: "foo",
expectedError: "unknown chain: foo, unable to retrieve a RPC client",
},
{
name: "Safe_v130 Bytecode Mismatch",
contractMetadataEth: remoteContractMetadata{
remoteContract: remoteContract{
Name: "Safe_v130",
Verified: true,
Deployments: deployments{
Op: common.Address{},
Eth: common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"),
},
DeploymentSalt: "0000000000000000000000000000000000000000000000000000000000000000",
Deployer: common.Address{},
ABI: "",
InitBytecode: "",
},
Package: "bindings",
InitBin: "",
DeployedBin: Permit2DeployedBytecode,
},
chain: "eth",
expectedError: "Safe_v130 deployment bytecode from RPC doesn't match bytecode from Etherscan.",
},
}
package main package bindgen
import ( import (
"encoding/json" "encoding/json"
...@@ -15,10 +15,10 @@ import ( ...@@ -15,10 +15,10 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/foundry" "github.com/ethereum-optimism/optimism/op-bindings/foundry"
) )
type bindGenGeneratorLocal struct { type BindGenGeneratorLocal struct {
bindGenGeneratorBase BindGenGeneratorBase
sourceMapsList string SourceMapsList string
forgeArtifactsPath string ForgeArtifactsPath string
} }
type localContractMetadata struct { type localContractMetadata struct {
...@@ -30,33 +30,33 @@ type localContractMetadata struct { ...@@ -30,33 +30,33 @@ type localContractMetadata struct {
HasImmutableReferences bool HasImmutableReferences bool
} }
func (generator *bindGenGeneratorLocal) generateBindings() error { func (generator *BindGenGeneratorLocal) GenerateBindings() error {
contracts, err := readContractList(generator.logger, generator.contractsListPath) contracts, err := readContractList(generator.Logger, generator.ContractsListPath)
if err != nil { if err != nil {
return fmt.Errorf("error reading contract list %s: %w", generator.contractsListPath, err) return fmt.Errorf("error reading contract list %s: %w", generator.ContractsListPath, err)
} }
if len(contracts.Local) == 0 { if len(contracts.Local) == 0 {
return fmt.Errorf("no contracts parsed from given contract list: %s", generator.contractsListPath) return fmt.Errorf("no contracts parsed from given contract list: %s", generator.ContractsListPath)
} }
return generator.processContracts(contracts.Local) return generator.processContracts(contracts.Local)
} }
func (generator *bindGenGeneratorLocal) processContracts(contracts []string) error { func (generator *BindGenGeneratorLocal) processContracts(contracts []string) error {
tempArtifactsDir, err := mkTempArtifactsDir(generator.logger) tempArtifactsDir, err := mkTempArtifactsDir(generator.Logger)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
err := os.RemoveAll(tempArtifactsDir) err := os.RemoveAll(tempArtifactsDir)
if err != nil { if err != nil {
generator.logger.Error("Error removing temporary artifact directory", "path", tempArtifactsDir, "err", err.Error()) generator.Logger.Error("Error removing temporary artifact directory", "path", tempArtifactsDir, "err", err.Error())
} else { } else {
generator.logger.Debug("Successfully removed temporary artifact directory") generator.Logger.Debug("Successfully removed temporary artifact directory")
} }
}() }()
sourceMapsList := strings.Split(generator.sourceMapsList, ",") sourceMapsList := strings.Split(generator.SourceMapsList, ",")
sourceMapsSet := make(map[string]struct{}) sourceMapsSet := make(map[string]struct{})
for _, k := range sourceMapsList { for _, k := range sourceMapsList {
sourceMapsSet[k] = struct{}{} sourceMapsSet[k] = struct{}{}
...@@ -70,19 +70,19 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err ...@@ -70,19 +70,19 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err
contractMetadataFileTemplate := template.Must(template.New("localContractMetadata").Parse(localContractMetadataTemplate)) contractMetadataFileTemplate := template.Must(template.New("localContractMetadata").Parse(localContractMetadataTemplate))
for _, contractName := range contracts { for _, contractName := range contracts {
generator.logger.Info("Generating bindings and metadata for local contract", "contract", contractName) generator.Logger.Info("Generating bindings and metadata for local contract", "contract", contractName)
forgeArtifact, err := generator.readForgeArtifact(contractName, contractArtifactPaths) forgeArtifact, err := generator.readForgeArtifact(contractName, contractArtifactPaths)
if err != nil { if err != nil {
return err return err
} }
abiFilePath, bytecodeFilePath, err := writeContractArtifacts(generator.logger, tempArtifactsDir, contractName, forgeArtifact.Abi, []byte(forgeArtifact.Bytecode.Object.String())) abiFilePath, bytecodeFilePath, err := writeContractArtifacts(generator.Logger, tempArtifactsDir, contractName, forgeArtifact.Abi, []byte(forgeArtifact.Bytecode.Object.String()))
if err != nil { if err != nil {
return err return err
} }
err = genContractBindings(generator.logger, generator.monorepoBasePath, abiFilePath, bytecodeFilePath, generator.bindingsPackageName, contractName) err = genContractBindings(generator.Logger, generator.MonorepoBasePath, abiFilePath, bytecodeFilePath, generator.BindingsPackageName, contractName)
if err != nil { if err != nil {
return err return err
} }
...@@ -104,7 +104,7 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err ...@@ -104,7 +104,7 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err
Name: contractName, Name: contractName,
StorageLayout: canonicalStorageStr, StorageLayout: canonicalStorageStr,
DeployedBin: forgeArtifact.DeployedBytecode.Object.String(), DeployedBin: forgeArtifact.DeployedBytecode.Object.String(),
Package: generator.bindingsPackageName, Package: generator.BindingsPackageName,
DeployedSourceMap: deployedSourceMap, DeployedSourceMap: deployedSourceMap,
HasImmutableReferences: hasImmutables, HasImmutableReferences: hasImmutables,
} }
...@@ -117,14 +117,14 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err ...@@ -117,14 +117,14 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err
return nil return nil
} }
func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]string, error) { func (generator *BindGenGeneratorLocal) getContractArtifactPaths() (map[string]string, error) {
// If some contracts have the same name then the path to their // If some contracts have the same name then the path to their
// artifact depends on their full import path. Scan over all artifacts // artifact depends on their full import path. Scan over all artifacts
// and hold a mapping from the contract name to the contract path. // and hold a mapping from the contract name to the contract path.
// Walk walks the directory deterministically, so the earliest instance // Walk walks the directory deterministically, so the earliest instance
// of the contract with the same name will be used // of the contract with the same name will be used
artifactPaths := make(map[string]string) artifactPaths := make(map[string]string)
if err := filepath.Walk(generator.forgeArtifactsPath, if err := filepath.Walk(generator.ForgeArtifactsPath,
func(path string, info os.FileInfo, err error) error { func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
...@@ -141,7 +141,7 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s ...@@ -141,7 +141,7 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s
if !ok { if !ok {
artifactPaths[sanitized] = path artifactPaths[sanitized] = path
} else { } else {
generator.logger.Warn("Multiple versions of forge artifacts exist, using lesser version", "contract", sanitized) generator.Logger.Warn("Multiple versions of forge artifacts exist, using lesser version", "contract", sanitized)
} }
} }
return nil return nil
...@@ -152,13 +152,13 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s ...@@ -152,13 +152,13 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s
return artifactPaths, nil return artifactPaths, nil
} }
func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, contractArtifactPaths map[string]string) (foundry.Artifact, error) { func (generator *BindGenGeneratorLocal) readForgeArtifact(contractName string, contractArtifactPaths map[string]string) (foundry.Artifact, error) {
var forgeArtifact foundry.Artifact var forgeArtifact foundry.Artifact
contractArtifactPath := path.Join(generator.forgeArtifactsPath, contractName+".sol", contractName+".json") contractArtifactPath := path.Join(generator.ForgeArtifactsPath, contractName+".sol", contractName+".json")
forgeArtifactRaw, err := os.ReadFile(contractArtifactPath) forgeArtifactRaw, err := os.ReadFile(contractArtifactPath)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
generator.logger.Debug("Cannot find forge-artifact at standard path, trying provided path", "contract", contractName, "standardPath", contractArtifactPath, "providedPath", contractArtifactPaths[contractName]) generator.Logger.Debug("Cannot find forge-artifact at standard path, trying provided path", "contract", contractName, "standardPath", contractArtifactPath, "providedPath", contractArtifactPaths[contractName])
contractArtifactPath = contractArtifactPaths[contractName] contractArtifactPath = contractArtifactPaths[contractName]
forgeArtifactRaw, err = os.ReadFile(contractArtifactPath) forgeArtifactRaw, err = os.ReadFile(contractArtifactPath)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
...@@ -166,7 +166,7 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c ...@@ -166,7 +166,7 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c
} }
} }
generator.logger.Debug("Using forge-artifact", "path", contractArtifactPath) generator.Logger.Debug("Using forge-artifact", "path", contractArtifactPath)
if err := json.Unmarshal(forgeArtifactRaw, &forgeArtifact); err != nil { if err := json.Unmarshal(forgeArtifactRaw, &forgeArtifact); err != nil {
return forgeArtifact, fmt.Errorf("failed to parse forge artifact of %q: %w", contractName, err) return forgeArtifact, fmt.Errorf("failed to parse forge artifact of %q: %w", contractName, err)
} }
...@@ -174,9 +174,9 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c ...@@ -174,9 +174,9 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c
return forgeArtifact, nil return forgeArtifact, nil
} }
func (generator *bindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact foundry.Artifact, sourceMapsSet map[string]struct{}, contractName string) (string, string, error) { func (generator *BindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact foundry.Artifact, sourceMapsSet map[string]struct{}, contractName string) (string, string, error) {
artifactStorageStruct := forgeArtifact.StorageLayout artifactStorageStruct := forgeArtifact.StorageLayout
canonicalStorageStruct := ast.CanonicalizeASTIDs(&artifactStorageStruct, generator.monorepoBasePath) canonicalStorageStruct := ast.CanonicalizeASTIDs(&artifactStorageStruct, generator.MonorepoBasePath)
canonicalStorageJson, err := json.Marshal(canonicalStorageStruct) canonicalStorageJson, err := json.Marshal(canonicalStorageStruct)
if err != nil { if err != nil {
return "", "", fmt.Errorf("error marshaling canonical storage: %w", err) return "", "", fmt.Errorf("error marshaling canonical storage: %w", err)
...@@ -191,8 +191,8 @@ func (generator *bindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact ...@@ -191,8 +191,8 @@ func (generator *bindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact
return deployedSourceMap, canonicalStorageStr, nil return deployedSourceMap, canonicalStorageStr, nil
} }
func (generator *bindGenGeneratorLocal) writeContractMetadata(contractMetaData localContractMetadata, contractName string, fileTemplate *template.Template) error { func (generator *BindGenGeneratorLocal) writeContractMetadata(contractMetaData localContractMetadata, contractName string, fileTemplate *template.Template) error {
metadataFilePath := filepath.Join(generator.metadataOut, strings.ToLower(contractName)+"_more.go") metadataFilePath := filepath.Join(generator.MetadataOut, strings.ToLower(contractName)+"_more.go")
metadataFile, err := os.OpenFile( metadataFile, err := os.OpenFile(
metadataFilePath, metadataFilePath,
os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.O_RDWR|os.O_CREATE|os.O_TRUNC,
...@@ -207,7 +207,7 @@ func (generator *bindGenGeneratorLocal) writeContractMetadata(contractMetaData l ...@@ -207,7 +207,7 @@ func (generator *bindGenGeneratorLocal) writeContractMetadata(contractMetaData l
return fmt.Errorf("error writing %s's contract metadata at %s: %w", contractName, metadataFilePath, err) return fmt.Errorf("error writing %s's contract metadata at %s: %w", contractName, metadataFilePath, err)
} }
generator.logger.Debug("Successfully wrote contract metadata", "contract", contractName, "path", metadataFilePath) generator.Logger.Debug("Successfully wrote contract metadata", "contract", contractName, "path", metadataFilePath)
return nil return nil
} }
......
package main package bindgen
import ( import (
"context" "context"
...@@ -10,15 +10,15 @@ import ( ...@@ -10,15 +10,15 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
) )
type bindGenGeneratorRemote struct { type BindGenGeneratorRemote struct {
bindGenGeneratorBase BindGenGeneratorBase
contractDataClients struct { ContractDataClients struct {
eth contractDataClient Eth contractDataClient
op contractDataClient Op contractDataClient
} }
rpcClients struct { RpcClients struct {
eth *ethclient.Client Eth *ethclient.Client
op *ethclient.Client Op *ethclient.Client
} }
tempArtifactsDir string tempArtifactsDir string
} }
...@@ -30,67 +30,67 @@ type contractDataClient interface { ...@@ -30,67 +30,67 @@ type contractDataClient interface {
FetchDeploymentTx(ctx context.Context, txHash string) (etherscan.Transaction, error) FetchDeploymentTx(ctx context.Context, txHash string) (etherscan.Transaction, error)
} }
type deployments struct { type Deployments struct {
Eth common.Address `json:"eth"` Eth common.Address `json:"eth"`
Op common.Address `json:"op"` Op common.Address `json:"op"`
} }
type remoteContract struct { type RemoteContract struct {
Name string `json:"name"` Name string `json:"name"`
Verified bool `json:"verified"` Verified bool `json:"verified"`
Deployments deployments `json:"deployments"` Deployments Deployments `json:"deployments"`
DeploymentSalt string `json:"deploymentSalt"` DeploymentSalt string `json:"deploymentSalt"`
Deployer common.Address `json:"deployer"` Deployer common.Address `json:"deployer"`
ABI string `json:"abi"` ABI string `json:"abi"`
InitBytecode string `json:"initBytecode"` InitBytecode string `json:"initBytecode"`
} }
type remoteContractMetadata struct { type RemoteContractMetadata struct {
remoteContract RemoteContract
Package string Package string
InitBin string InitBin string
DeployedBin string DeployedBin string
} }
func (generator *bindGenGeneratorRemote) generateBindings() error { func (generator *BindGenGeneratorRemote) GenerateBindings() error {
contracts, err := readContractList(generator.logger, generator.contractsListPath) contracts, err := readContractList(generator.Logger, generator.ContractsListPath)
if err != nil { if err != nil {
return fmt.Errorf("error reading contract list %s: %w", generator.contractsListPath, err) return fmt.Errorf("error reading contract list %s: %w", generator.ContractsListPath, err)
} }
if len(contracts.Remote) == 0 { if len(contracts.Remote) == 0 {
return fmt.Errorf("no contracts parsed from given contract list: %s", generator.contractsListPath) return fmt.Errorf("no contracts parsed from given contract list: %s", generator.ContractsListPath)
} }
return generator.processContracts(contracts.Remote) return generator.processContracts(contracts.Remote)
} }
func (generator *bindGenGeneratorRemote) processContracts(contracts []remoteContract) error { func (generator *BindGenGeneratorRemote) processContracts(contracts []RemoteContract) error {
var err error var err error
generator.tempArtifactsDir, err = mkTempArtifactsDir(generator.logger) generator.tempArtifactsDir, err = mkTempArtifactsDir(generator.Logger)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
err := os.RemoveAll(generator.tempArtifactsDir) err := os.RemoveAll(generator.tempArtifactsDir)
if err != nil { if err != nil {
generator.logger.Error("Error removing temporary artifact directory", "path", generator.tempArtifactsDir, "err", err.Error()) generator.Logger.Error("Error removing temporary artifact directory", "path", generator.tempArtifactsDir, "err", err.Error())
} else { } else {
generator.logger.Debug("Successfully removed temporary artifact directory") generator.Logger.Debug("Successfully removed temporary artifact directory")
} }
}() }()
for _, contract := range contracts { for _, contract := range contracts {
generator.logger.Info("Generating bindings and metadata for remote contract", "contract", contract.Name) generator.Logger.Info("Generating bindings and metadata for remote contract", "contract", contract.Name)
contractMetadata := remoteContractMetadata{ contractMetadata := RemoteContractMetadata{
remoteContract: remoteContract{ RemoteContract: RemoteContract{
Name: contract.Name, Name: contract.Name,
Deployments: contract.Deployments, Deployments: contract.Deployments,
DeploymentSalt: contract.DeploymentSalt, DeploymentSalt: contract.DeploymentSalt,
ABI: contract.ABI, ABI: contract.ABI,
Verified: contract.Verified, Verified: contract.Verified,
}, },
Package: generator.bindingsPackageName, Package: generator.BindingsPackageName,
} }
var err error var err error
......
package main package bindgen
import ( import (
"bytes" "bytes"
...@@ -15,57 +15,57 @@ import ( ...@@ -15,57 +15,57 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
) )
type contractData struct { type ContractData struct {
abi string Abi string
deployedBin string DeployedBin string
deploymentTx etherscan.Transaction DeploymentTx etherscan.Transaction
} }
func (generator *bindGenGeneratorRemote) standardHandler(contractMetadata *remoteContractMetadata) error { func (generator *BindGenGeneratorRemote) standardHandler(contractMetadata *RemoteContractMetadata) error {
fetchedData, err := generator.fetchContractData(contractMetadata.Verified, "eth", contractMetadata.Deployments.Eth.Hex()) fetchedData, err := generator.FetchContractData(contractMetadata.Verified, "eth", contractMetadata.Deployments.Eth.Hex())
if err != nil { if err != nil {
return err return err
} }
contractMetadata.DeployedBin = fetchedData.deployedBin contractMetadata.DeployedBin = fetchedData.DeployedBin
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil { if err = generator.CompareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil {
return err return err
} }
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil { if err = generator.CompareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil {
return err return err
} }
// If ABI was explicitly provided by config, don't overwrite // If ABI was explicitly provided by config, don't overwrite
if contractMetadata.ABI == "" { if contractMetadata.ABI == "" {
contractMetadata.ABI = fetchedData.abi contractMetadata.ABI = fetchedData.Abi
} else if fetchedData.abi != "" && contractMetadata.ABI != fetchedData.abi { } else if fetchedData.Abi != "" && contractMetadata.ABI != fetchedData.Abi {
generator.logger.Debug("ABIs", "given", contractMetadata.ABI, "fetched", fetchedData.abi) generator.Logger.Debug("ABIs", "given", contractMetadata.ABI, "fetched", fetchedData.Abi)
return fmt.Errorf("the given ABI for %s differs from what was fetched from Etherscan", contractMetadata.Name) return fmt.Errorf("the given ABI for %s differs from what was fetched from Etherscan", contractMetadata.Name)
} }
if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.deploymentTx.Input, contractMetadata.DeploymentSalt); err != nil { if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.DeploymentTx.Input, contractMetadata.DeploymentSalt); err != nil {
return err return err
} }
if err := generator.compareInitBytecodeWithOp(contractMetadata, true); err != nil { if err := generator.CompareInitBytecodeWithOp(contractMetadata, true); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
if err := generator.compareDeployedBytecodeWithOp(contractMetadata, true); err != nil { if err := generator.CompareDeployedBytecodeWithOp(contractMetadata, true); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate) return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate)
} }
func (generator *bindGenGeneratorRemote) create2DeployerHandler(contractMetadata *remoteContractMetadata) error { func (generator *BindGenGeneratorRemote) create2DeployerHandler(contractMetadata *RemoteContractMetadata) error {
fetchedData, err := generator.fetchContractData(contractMetadata.Verified, "eth", contractMetadata.Deployments.Eth.Hex()) fetchedData, err := generator.FetchContractData(contractMetadata.Verified, "eth", contractMetadata.Deployments.Eth.Hex())
if err != nil { if err != nil {
return err return err
} }
contractMetadata.ABI = fetchedData.abi contractMetadata.ABI = fetchedData.Abi
contractMetadata.DeployedBin = fetchedData.deployedBin contractMetadata.DeployedBin = fetchedData.DeployedBin
if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.deploymentTx.Input, contractMetadata.DeploymentSalt); err != nil { if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.DeploymentTx.Input, contractMetadata.DeploymentSalt); err != nil {
return err return err
} }
...@@ -73,135 +73,135 @@ func (generator *bindGenGeneratorRemote) create2DeployerHandler(contractMetadata ...@@ -73,135 +73,135 @@ func (generator *bindGenGeneratorRemote) create2DeployerHandler(contractMetadata
// because we're predeploying a modified version of Create2Deployer that has not yet been // because we're predeploying a modified version of Create2Deployer that has not yet been
// deployed to OP. // deployed to OP.
// For context: https://github.com/ethereum-optimism/op-geth/pull/126 // For context: https://github.com/ethereum-optimism/op-geth/pull/126
if err := generator.compareInitBytecodeWithOp(contractMetadata, false); err != nil { if err := generator.CompareInitBytecodeWithOp(contractMetadata, false); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
if err := generator.compareDeployedBytecodeWithOp(contractMetadata, false); err != nil { if err := generator.CompareDeployedBytecodeWithOp(contractMetadata, false); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate) return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate)
} }
func (generator *bindGenGeneratorRemote) multiSendHandler(contractMetadata *remoteContractMetadata) error { func (generator *BindGenGeneratorRemote) multiSendHandler(contractMetadata *RemoteContractMetadata) error {
// MultiSend has an immutable that resolves to this(address). // MultiSend has an immutable that resolves to this(address).
// Because we're predeploying MultiSend to the same address as on OP, // Because we're predeploying MultiSend to the same address as on OP,
// we can use the deployed bytecode directly for the predeploy // we can use the deployed bytecode directly for the predeploy
fetchedData, err := generator.fetchContractData(contractMetadata.Verified, "op", contractMetadata.Deployments.Op.Hex()) fetchedData, err := generator.FetchContractData(contractMetadata.Verified, "op", contractMetadata.Deployments.Op.Hex())
if err != nil { if err != nil {
return err return err
} }
contractMetadata.ABI = fetchedData.abi contractMetadata.ABI = fetchedData.Abi
contractMetadata.DeployedBin = fetchedData.deployedBin contractMetadata.DeployedBin = fetchedData.DeployedBin
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil { if err = generator.CompareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil {
return err return err
} }
if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.deploymentTx.Input, contractMetadata.DeploymentSalt); err != nil { if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.DeploymentTx.Input, contractMetadata.DeploymentSalt); err != nil {
return err return err
} }
return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate) return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate)
} }
func (generator *bindGenGeneratorRemote) senderCreatorHandler(contractMetadata *remoteContractMetadata) error { func (generator *BindGenGeneratorRemote) senderCreatorHandler(contractMetadata *RemoteContractMetadata) error {
var err error var err error
contractMetadata.DeployedBin, err = generator.contractDataClients.eth.FetchDeployedBytecode(context.Background(), contractMetadata.Deployments.Eth.Hex()) contractMetadata.DeployedBin, err = generator.ContractDataClients.Eth.FetchDeployedBytecode(context.Background(), contractMetadata.Deployments.Eth.Hex())
if err != nil { if err != nil {
return fmt.Errorf("error fetching deployed bytecode: %w", err) return fmt.Errorf("error fetching deployed bytecode: %w", err)
} }
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil { if err = generator.CompareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil {
return err return err
} }
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil { if err = generator.CompareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil {
return err return err
} }
// The SenderCreator contract is deployed by EntryPoint, so the transaction data // The SenderCreator contract is deployed by EntryPoint, so the transaction data
// from the deployment transaction is for the entire EntryPoint deployment. // from the deployment transaction is for the entire EntryPoint deployment.
// So, we're manually providing the initialization bytecode and therefore it isn't being compared here // So, we're manually providing the initialization bytecode and therefore it isn't being compared here
if err := generator.compareInitBytecodeWithOp(contractMetadata, false); err != nil { if err := generator.CompareInitBytecodeWithOp(contractMetadata, false); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
if err := generator.compareDeployedBytecodeWithOp(contractMetadata, true); err != nil { if err := generator.CompareDeployedBytecodeWithOp(contractMetadata, true); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate) return generator.writeAllOutputs(contractMetadata, remoteContractMetadataTemplate)
} }
func (generator *bindGenGeneratorRemote) permit2Handler(contractMetadata *remoteContractMetadata) error { func (generator *BindGenGeneratorRemote) permit2Handler(contractMetadata *RemoteContractMetadata) error {
fetchedData, err := generator.fetchContractData(contractMetadata.Verified, "eth", contractMetadata.Deployments.Eth.Hex()) fetchedData, err := generator.FetchContractData(contractMetadata.Verified, "eth", contractMetadata.Deployments.Eth.Hex())
if err != nil { if err != nil {
return err return err
} }
contractMetadata.ABI = fetchedData.abi contractMetadata.ABI = fetchedData.Abi
contractMetadata.DeployedBin = fetchedData.deployedBin contractMetadata.DeployedBin = fetchedData.DeployedBin
if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.deploymentTx.Input, contractMetadata.DeploymentSalt); err != nil { if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.DeploymentTx.Input, contractMetadata.DeploymentSalt); err != nil {
return err return err
} }
if !strings.EqualFold(contractMetadata.Deployer.Hex(), fetchedData.deploymentTx.To) { if !strings.EqualFold(contractMetadata.Deployer.Hex(), fetchedData.DeploymentTx.To) {
return fmt.Errorf( return fmt.Errorf(
"expected deployer address: %s doesn't match the to address: %s for Permit2's proxy deployment transaction", "expected deployer address: %s doesn't match the to address: %s for Permit2's proxy deployment transaction",
contractMetadata.Deployer.Hex(), contractMetadata.Deployer.Hex(),
fetchedData.deploymentTx.To, fetchedData.DeploymentTx.To,
) )
} }
if err := generator.compareInitBytecodeWithOp(contractMetadata, true); err != nil { if err := generator.CompareInitBytecodeWithOp(contractMetadata, true); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
// We're asserting the deployed bytecode doesn't match, because Permit2 has immutable Solidity variables that // We're asserting the deployed bytecode doesn't match, because Permit2 has immutable Solidity variables that
// are dependent on block.chainid // are dependent on block.chainid
if err := generator.compareDeployedBytecodeWithOp(contractMetadata, false); err != nil { if err := generator.CompareDeployedBytecodeWithOp(contractMetadata, false); err != nil {
return fmt.Errorf("%s: %w", contractMetadata.Name, err) return fmt.Errorf("%s: %w", contractMetadata.Name, err)
} }
return generator.writeAllOutputs(contractMetadata, permit2MetadataTemplate) return generator.writeAllOutputs(contractMetadata, permit2MetadataTemplate)
} }
func (generator *bindGenGeneratorRemote) fetchContractData(contractVerified bool, chain, deploymentAddress string) (contractData, error) { func (generator *BindGenGeneratorRemote) FetchContractData(contractVerified bool, chain, deploymentAddress string) (ContractData, error) {
var data contractData var data ContractData
var err error var err error
var client contractDataClient var client contractDataClient
switch chain { switch chain {
case "eth": case "eth":
client = generator.contractDataClients.eth client = generator.ContractDataClients.Eth
case "op": case "op":
client = generator.contractDataClients.op client = generator.ContractDataClients.Op
default: default:
return data, fmt.Errorf("unknown chain, unable to retrieve a contract data client for chain: %s", chain) return data, fmt.Errorf("unknown chain, unable to retrieve a contract data client for chain: %s", chain)
} }
if contractVerified { if contractVerified {
data.abi, err = client.FetchAbi(context.Background(), deploymentAddress) data.Abi, err = client.FetchAbi(context.Background(), deploymentAddress)
if err != nil { if err != nil {
return contractData{}, fmt.Errorf("error fetching ABI: %w", err) return ContractData{}, fmt.Errorf("error fetching ABI: %w", err)
} }
} }
data.deployedBin, err = client.FetchDeployedBytecode(context.Background(), deploymentAddress) data.DeployedBin, err = client.FetchDeployedBytecode(context.Background(), deploymentAddress)
if err != nil { if err != nil {
return contractData{}, fmt.Errorf("error fetching deployed bytecode: %w", err) return ContractData{}, fmt.Errorf("error fetching deployed bytecode: %w", err)
} }
deploymentTxHash, err := client.FetchDeploymentTxHash(context.Background(), deploymentAddress) deploymentTxHash, err := client.FetchDeploymentTxHash(context.Background(), deploymentAddress)
if err != nil { if err != nil {
return contractData{}, fmt.Errorf("error fetching deployment transaction hash: %w", err) return ContractData{}, fmt.Errorf("error fetching deployment transaction hash: %w", err)
} }
data.deploymentTx, err = client.FetchDeploymentTx(context.Background(), deploymentTxHash) data.DeploymentTx, err = client.FetchDeploymentTx(context.Background(), deploymentTxHash)
if err != nil { if err != nil {
return contractData{}, fmt.Errorf("error fetching deployment transaction data: %w", err) return ContractData{}, fmt.Errorf("error fetching deployment transaction data: %w", err)
} }
return data, nil return data, nil
} }
func (generator *bindGenGeneratorRemote) removeDeploymentSalt(deploymentData, deploymentSalt string) (string, error) { func (generator *BindGenGeneratorRemote) removeDeploymentSalt(deploymentData, deploymentSalt string) (string, error) {
if deploymentSalt == "" { if deploymentSalt == "" {
return deploymentData, nil return deploymentData, nil
} }
...@@ -219,7 +219,7 @@ func (generator *bindGenGeneratorRemote) removeDeploymentSalt(deploymentData, de ...@@ -219,7 +219,7 @@ func (generator *bindGenGeneratorRemote) removeDeploymentSalt(deploymentData, de
return re.ReplaceAllString(deploymentData, ""), nil return re.ReplaceAllString(deploymentData, ""), nil
} }
func (generator *bindGenGeneratorRemote) compareInitBytecodeWithOp(contractMetadataEth *remoteContractMetadata, initCodeShouldMatch bool) error { func (generator *BindGenGeneratorRemote) CompareInitBytecodeWithOp(contractMetadataEth *RemoteContractMetadata, initCodeShouldMatch bool) error {
if contractMetadataEth.InitBin == "" { if contractMetadataEth.InitBin == "" {
return fmt.Errorf("no initialization bytecode provided for ETH deployment for comparison") return fmt.Errorf("no initialization bytecode provided for ETH deployment for comparison")
} }
...@@ -230,36 +230,36 @@ func (generator *bindGenGeneratorRemote) compareInitBytecodeWithOp(contractMetad ...@@ -230,36 +230,36 @@ func (generator *bindGenGeneratorRemote) compareInitBytecodeWithOp(contractMetad
} }
// Passing false here, because true will retrieve contract's ABI, but we don't need it for bytecode comparison // Passing false here, because true will retrieve contract's ABI, but we don't need it for bytecode comparison
opContractData, err := generator.fetchContractData(false, "op", contractMetadataEth.Deployments.Op.Hex()) opContractData, err := generator.FetchContractData(false, "op", contractMetadataEth.Deployments.Op.Hex())
if err != nil { if err != nil {
return err return err
} }
if opContractData.deploymentTx.Input, err = generator.removeDeploymentSalt(opContractData.deploymentTx.Input, contractMetadataEth.DeploymentSalt); err != nil { if opContractData.DeploymentTx.Input, err = generator.removeDeploymentSalt(opContractData.DeploymentTx.Input, contractMetadataEth.DeploymentSalt); err != nil {
return err return err
} }
initCodeComparison := strings.EqualFold(contractMetadataEth.InitBin, opContractData.deploymentTx.Input) initCodeComparison := strings.EqualFold(contractMetadataEth.InitBin, opContractData.DeploymentTx.Input)
if initCodeShouldMatch && !initCodeComparison { if initCodeShouldMatch && !initCodeComparison {
return fmt.Errorf( return fmt.Errorf(
"expected initialization bytecode to match on Ethereum and Optimism, but it doesn't. contract=%s bytecodeEth=%s bytecodeOp=%s", "expected initialization bytecode to match on Ethereum and Optimism, but it doesn't. contract=%s bytecodeEth=%s bytecodeOp=%s",
contractMetadataEth.Name, contractMetadataEth.Name,
contractMetadataEth.InitBin, contractMetadataEth.InitBin,
opContractData.deploymentTx.Input, opContractData.DeploymentTx.Input,
) )
} else if !initCodeShouldMatch && initCodeComparison { } else if !initCodeShouldMatch && initCodeComparison {
return fmt.Errorf( return fmt.Errorf(
"expected initialization bytecode on Ethereum to not match on Optimism, but it did. contract=%s bytecodeEth=%s bytecodeOp=%s", "expected initialization bytecode on Ethereum to not match on Optimism, but it did. contract=%s bytecodeEth=%s bytecodeOp=%s",
contractMetadataEth.Name, contractMetadataEth.Name,
contractMetadataEth.InitBin, contractMetadataEth.InitBin,
opContractData.deploymentTx.Input, opContractData.DeploymentTx.Input,
) )
} }
return nil return nil
} }
func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithOp(contractMetadataEth *remoteContractMetadata, deployedCodeShouldMatch bool) error { func (generator *BindGenGeneratorRemote) CompareDeployedBytecodeWithOp(contractMetadataEth *RemoteContractMetadata, deployedCodeShouldMatch bool) error {
if contractMetadataEth.DeployedBin == "" { if contractMetadataEth.DeployedBin == "" {
return fmt.Errorf("no deployed bytecode provided for ETH deployment for comparison") return fmt.Errorf("no deployed bytecode provided for ETH deployment for comparison")
} }
...@@ -270,38 +270,38 @@ func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithOp(contractM ...@@ -270,38 +270,38 @@ func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithOp(contractM
} }
// Passing false here, because true will retrieve contract's ABI, but we don't need it for bytecode comparison // Passing false here, because true will retrieve contract's ABI, but we don't need it for bytecode comparison
opContractData, err := generator.fetchContractData(false, "op", contractMetadataEth.Deployments.Op.Hex()) opContractData, err := generator.FetchContractData(false, "op", contractMetadataEth.Deployments.Op.Hex())
if err != nil { if err != nil {
return err return err
} }
deployedCodeComparison := strings.EqualFold(contractMetadataEth.DeployedBin, opContractData.deployedBin) deployedCodeComparison := strings.EqualFold(contractMetadataEth.DeployedBin, opContractData.DeployedBin)
if deployedCodeShouldMatch && !deployedCodeComparison { if deployedCodeShouldMatch && !deployedCodeComparison {
return fmt.Errorf( return fmt.Errorf(
"expected deployed bytecode to match on Ethereum and Optimism, but it doesn't. contract=%s bytecodeEth=%s bytecodeOp=%s", "expected deployed bytecode to match on Ethereum and Optimism, but it doesn't. contract=%s bytecodeEth=%s bytecodeOp=%s",
contractMetadataEth.Name, contractMetadataEth.Name,
contractMetadataEth.DeployedBin, contractMetadataEth.DeployedBin,
opContractData.deployedBin, opContractData.DeployedBin,
) )
} else if !deployedCodeShouldMatch && deployedCodeComparison { } else if !deployedCodeShouldMatch && deployedCodeComparison {
return fmt.Errorf( return fmt.Errorf(
"expected deployed bytecode on Ethereum to not match on Optimism, but it does. contract=%s bytecodeEth=%s bytecodeOp=%s", "expected deployed bytecode on Ethereum to not match on Optimism, but it does. contract=%s bytecodeEth=%s bytecodeOp=%s",
contractMetadataEth.Name, contractMetadataEth.Name,
contractMetadataEth.DeployedBin, contractMetadataEth.DeployedBin,
opContractData.deployedBin, opContractData.DeployedBin,
) )
} }
return nil return nil
} }
func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contractMetadata *remoteContractMetadata, chain string) error { func (generator *BindGenGeneratorRemote) CompareDeployedBytecodeWithRpc(contractMetadata *RemoteContractMetadata, chain string) error {
var client *ethclient.Client var client *ethclient.Client
switch chain { switch chain {
case "eth": case "eth":
client = generator.rpcClients.eth client = generator.RpcClients.Eth
case "op": case "op":
client = generator.rpcClients.op client = generator.RpcClients.Op
default: default:
return fmt.Errorf("unknown chain: %s, unable to retrieve a RPC client", chain) return fmt.Errorf("unknown chain: %s, unable to retrieve a RPC client", chain)
} }
...@@ -313,7 +313,7 @@ func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contract ...@@ -313,7 +313,7 @@ func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contract
case "op": case "op":
deployment = contractMetadata.Deployments.Op deployment = contractMetadata.Deployments.Op
default: default:
generator.logger.Warn("Unable to compare bytecode from Etherscan against RPC client, no deployment address provided for chain", "chain", chain) generator.Logger.Warn("Unable to compare bytecode from Etherscan against RPC client, no deployment address provided for chain", "chain", chain)
} }
if deployment != (common.Address{}) { if deployment != (common.Address{}) {
...@@ -330,28 +330,28 @@ func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contract ...@@ -330,28 +330,28 @@ func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contract
return nil return nil
} }
func (generator *bindGenGeneratorRemote) writeAllOutputs(contractMetadata *remoteContractMetadata, fileTemplate string) error { func (generator *BindGenGeneratorRemote) writeAllOutputs(contractMetadata *RemoteContractMetadata, fileTemplate string) error {
abiFilePath, bytecodeFilePath, err := writeContractArtifacts( abiFilePath, bytecodeFilePath, err := writeContractArtifacts(
generator.logger, generator.tempArtifactsDir, contractMetadata.Name, generator.Logger, generator.tempArtifactsDir, contractMetadata.Name,
[]byte(contractMetadata.ABI), []byte(contractMetadata.InitBin), []byte(contractMetadata.ABI), []byte(contractMetadata.InitBin),
) )
if err != nil { if err != nil {
return err return err
} }
err = genContractBindings(generator.logger, generator.monorepoBasePath, abiFilePath, bytecodeFilePath, generator.bindingsPackageName, contractMetadata.Name) err = genContractBindings(generator.Logger, generator.MonorepoBasePath, abiFilePath, bytecodeFilePath, generator.BindingsPackageName, contractMetadata.Name)
if err != nil { if err != nil {
return err return err
} }
return generator.writeContractMetadata( return generator.writeContractMetadata(
contractMetadata, contractMetadata,
template.Must(template.New("remoteContractMetadata").Parse(fileTemplate)), template.Must(template.New("RemoteContractMetadata").Parse(fileTemplate)),
) )
} }
func (generator *bindGenGeneratorRemote) writeContractMetadata(contractMetadata *remoteContractMetadata, fileTemplate *template.Template) error { func (generator *BindGenGeneratorRemote) writeContractMetadata(contractMetadata *RemoteContractMetadata, fileTemplate *template.Template) error {
metadataFilePath := filepath.Join(generator.metadataOut, strings.ToLower(contractMetadata.Name)+"_more.go") metadataFilePath := filepath.Join(generator.MetadataOut, strings.ToLower(contractMetadata.Name)+"_more.go")
var existingOutput []byte var existingOutput []byte
if _, err := os.Stat(metadataFilePath); err == nil { if _, err := os.Stat(metadataFilePath); err == nil {
...@@ -383,15 +383,15 @@ func (generator *bindGenGeneratorRemote) writeContractMetadata(contractMetadata ...@@ -383,15 +383,15 @@ func (generator *bindGenGeneratorRemote) writeContractMetadata(contractMetadata
} }
if bytes.Equal(existingOutput, newOutput) { if bytes.Equal(existingOutput, newOutput) {
generator.logger.Debug("No changes detected in the contract metadata", "contract", contractMetadata.Name) generator.Logger.Debug("No changes detected in the contract metadata", "contract", contractMetadata.Name)
} else { } else {
generator.logger.Warn("Changes detected in the contract metadata, old metadata has been overwritten", "contract", contractMetadata.Name) generator.Logger.Warn("Changes detected in the contract metadata, old metadata has been overwritten", "contract", contractMetadata.Name)
} }
} else { } else {
generator.logger.Debug("No existing contract metadata found, skipping comparison", "contract", contractMetadata.Name) generator.Logger.Debug("No existing contract metadata found, skipping comparison", "contract", contractMetadata.Name)
} }
generator.logger.Debug("Successfully wrote contract metadata", "contract", contractMetadata.Name, "path", metadataFilePath) generator.Logger.Debug("Successfully wrote contract metadata", "contract", contractMetadata.Name, "path", metadataFilePath)
return nil return nil
} }
......
package main package bindgen
import ( import (
"fmt"
"os"
"reflect"
"strings"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var generator bindGenGeneratorRemote = bindGenGeneratorRemote{} var generator BindGenGeneratorRemote = BindGenGeneratorRemote{}
func configureGenerator(t *testing.T) error {
if os.Getenv("RUN_E2E") == "" {
t.Log("Not running test, RUN_E2E env not set")
t.Skip()
}
generator.contractDataClients.eth = etherscan.NewEthereumClient(os.Getenv("ETHERSCAN_APIKEY_ETH"))
generator.contractDataClients.op = etherscan.NewOptimismClient(os.Getenv("ETHERSCAN_APIKEY_OP"))
var err error
if generator.rpcClients.eth, err = ethclient.Dial(os.Getenv("RPC_URL_ETH")); err != nil {
return fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.rpcClients.op, err = ethclient.Dial(os.Getenv("RPC_URL_OP")); err != nil {
return fmt.Errorf("error initializing Optimism client: %w", err)
}
return nil
}
func TestFetchContractData(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTests {
t.Run(tt.name, func(t *testing.T) {
contractData, err := generator.fetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(contractData, tt.expectedContractData) {
t.Errorf("Retrieved contract data doesn't match expected. Expected: %s Retrieved: %s", tt.expectedContractData, contractData)
}
})
}
}
func TestFetchContractDataFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTestsFailures {
t.Run(tt.name, func(t *testing.T) {
_, err := generator.fetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestRemoveDeploymentSalt(t *testing.T) { func TestRemoveDeploymentSalt(t *testing.T) {
for _, tt := range removeDeploymentSaltTests { for _, tt := range removeDeploymentSaltTests {
...@@ -90,111 +25,3 @@ func TestRemoveDeploymentSaltFailures(t *testing.T) { ...@@ -90,111 +25,3 @@ func TestRemoveDeploymentSaltFailures(t *testing.T) {
}) })
} }
} }
func TestCompareInitBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareInitBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithRpc(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithRpcFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
package main package bindgen
import ( import (
"bufio" "bufio"
...@@ -13,9 +13,17 @@ import ( ...@@ -13,9 +13,17 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
type BindGenGeneratorBase struct {
MetadataOut string
BindingsPackageName string
MonorepoBasePath string
ContractsListPath string
Logger log.Logger
}
type contractsList struct { type contractsList struct {
Local []string `json:"local"` Local []string `json:"local"`
Remote []remoteContract `json:"remote"` Remote []RemoteContract `json:"remote"`
} }
// readContractList reads a JSON file from the given `filePath` and unmarshals // readContractList reads a JSON file from the given `filePath` and unmarshals
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/ethereum-optimism/optimism/op-bindings/bindgen"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan" "github.com/ethereum-optimism/optimism/op-bindings/etherscan"
op_service "github.com/ethereum-optimism/optimism/op-service" op_service "github.com/ethereum-optimism/optimism/op-service"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
...@@ -12,14 +13,6 @@ import ( ...@@ -12,14 +13,6 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
type bindGenGeneratorBase struct {
metadataOut string
bindingsPackageName string
monorepoBasePath string
contractsListPath string
logger log.Logger
}
const ( const (
// Base Flags // Base Flags
MetadataOutFlagName = "metadata-out" MetadataOutFlagName = "metadata-out"
...@@ -92,7 +85,7 @@ func generateBindings(c *cli.Context) error { ...@@ -92,7 +85,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := localBindingsGenerator.generateBindings(); err != nil { if err := localBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating local bindings: %w", err) return fmt.Errorf("error generating local bindings: %w", err)
} }
...@@ -100,7 +93,7 @@ func generateBindings(c *cli.Context) error { ...@@ -100,7 +93,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := remoteBindingsGenerator.generateBindings(); err != nil { if err := remoteBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating remote bindings: %w", err) return fmt.Errorf("error generating remote bindings: %w", err)
} }
...@@ -110,7 +103,7 @@ func generateBindings(c *cli.Context) error { ...@@ -110,7 +103,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := localBindingsGenerator.generateBindings(); err != nil { if err := localBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating local bindings: %w", err) return fmt.Errorf("error generating local bindings: %w", err)
} }
return nil return nil
...@@ -119,7 +112,7 @@ func generateBindings(c *cli.Context) error { ...@@ -119,7 +112,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := remoteBindingsGenerator.generateBindings(); err != nil { if err := remoteBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating remote bindings: %w", err) return fmt.Errorf("error generating remote bindings: %w", err)
} }
return nil return nil
...@@ -128,55 +121,55 @@ func generateBindings(c *cli.Context) error { ...@@ -128,55 +121,55 @@ func generateBindings(c *cli.Context) error {
} }
} }
func parseConfigBase(logger log.Logger, c *cli.Context) (bindGenGeneratorBase, error) { func parseConfigBase(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorBase, error) {
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
return bindGenGeneratorBase{}, err return bindgen.BindGenGeneratorBase{}, err
} }
monoRepoPath, err := op_service.FindMonorepoRoot(cwd) monoRepoPath, err := op_service.FindMonorepoRoot(cwd)
if err != nil { if err != nil {
return bindGenGeneratorBase{}, err return bindgen.BindGenGeneratorBase{}, err
} }
return bindGenGeneratorBase{ return bindgen.BindGenGeneratorBase{
metadataOut: c.String(MetadataOutFlagName), MetadataOut: c.String(MetadataOutFlagName),
bindingsPackageName: c.String(BindingsPackageNameFlagName), BindingsPackageName: c.String(BindingsPackageNameFlagName),
monorepoBasePath: monoRepoPath, MonorepoBasePath: monoRepoPath,
contractsListPath: c.String(ContractsListFlagName), ContractsListPath: c.String(ContractsListFlagName),
logger: logger, Logger: logger,
}, nil }, nil
} }
func parseConfigLocal(logger log.Logger, c *cli.Context) (bindGenGeneratorLocal, error) { func parseConfigLocal(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorLocal, error) {
baseConfig, err := parseConfigBase(logger, c) baseConfig, err := parseConfigBase(logger, c)
if err != nil { if err != nil {
return bindGenGeneratorLocal{}, err return bindgen.BindGenGeneratorLocal{}, err
} }
return bindGenGeneratorLocal{ return bindgen.BindGenGeneratorLocal{
bindGenGeneratorBase: baseConfig, BindGenGeneratorBase: baseConfig,
sourceMapsList: c.String(SourceMapsListFlagName), SourceMapsList: c.String(SourceMapsListFlagName),
forgeArtifactsPath: c.String(ForgeArtifactsFlagName), ForgeArtifactsPath: c.String(ForgeArtifactsFlagName),
}, nil }, nil
} }
func parseConfigRemote(logger log.Logger, c *cli.Context) (bindGenGeneratorRemote, error) { func parseConfigRemote(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorRemote, error) {
baseConfig, err := parseConfigBase(logger, c) baseConfig, err := parseConfigBase(logger, c)
if err != nil { if err != nil {
return bindGenGeneratorRemote{}, err return bindgen.BindGenGeneratorRemote{}, err
} }
generator := bindGenGeneratorRemote{ generator := bindgen.BindGenGeneratorRemote{
bindGenGeneratorBase: baseConfig, BindGenGeneratorBase: baseConfig,
} }
generator.contractDataClients.eth = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName)) generator.ContractDataClients.Eth = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName))
generator.contractDataClients.op = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName)) generator.ContractDataClients.Op = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName))
if generator.rpcClients.eth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil { if generator.RpcClients.Eth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err) return bindgen.BindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err)
} }
if generator.rpcClients.op, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil { if generator.RpcClients.Op, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err) return bindgen.BindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err)
} }
return generator, nil return generator, nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment