Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
816e425c
Unverified
Commit
816e425c
authored
Dec 15, 2023
by
Wyatt Barnes
Committed by
GitHub
Dec 15, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Init remote contract generation (#8281)
parent
54d5ab5b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
639 additions
and
5 deletions
+639
-5
Makefile
op-bindings/Makefile
+28
-0
artifacts.json
op-bindings/artifacts.json
+99
-0
generator_remote.go
op-bindings/bindgen/generator_remote.go
+124
-0
main.go
op-bindings/bindgen/main.go
+75
-0
remote_handlers.go
op-bindings/bindgen/remote_handlers.go
+310
-0
utils.go
op-bindings/bindgen/utils.go
+2
-1
client.go
op-bindings/etherscan/client.go
+1
-4
No files found.
op-bindings/Makefile
View file @
816e425c
...
...
@@ -5,6 +5,8 @@ monorepo-base := $(shell dirname $(realpath .))
contracts-dir
:=
$
(
monorepo-base
)
/packages/contracts-bedrock
contracts-list
:=
./artifacts.json
log-level
:=
info
ETHERSCAN_APIKEY_ETH
?=
ETHERSCAN_APIKEY_OP
?=
all
:
version mkdir bindings
...
...
@@ -21,6 +23,21 @@ bindings: bindgen-local
bindings-build
:
bindgen-generate-local
bindgen
:
compile bindgen-generate-all
bindgen-generate-all
:
go run ./bindgen/
\
generate
\
--metadata-out
./
$(pkg)
\
--bindings-package
$(pkg)
\
--contracts-list
$
(
contracts-list
)
\
--log
.level
$
(
log-level
)
\
all
\
--source-maps-list
MIPS,PreimageOracle
\
--forge-artifacts
$
(
contracts-dir
)
/forge-artifacts
\
--etherscan
.apikey.eth
$(ETHERSCAN_APIKEY_ETH)
\
--etherscan
.apikey.op
$(ETHERSCAN_APIKEY_OP)
bindgen-local
:
compile bindgen-generate-local
bindgen-generate-local
:
...
...
@@ -34,6 +51,17 @@ bindgen-generate-local:
--source-maps-list
MIPS,PreimageOracle
\
--forge-artifacts
$
(
contracts-dir
)
/forge-artifacts
bindgen-remote
:
go run ./bindgen/
\
generate
\
--metadata-out
./
$(pkg)
\
--bindings-package
$(pkg)
\
--contracts-list
$
(
contracts-list
)
\
--log
.level
$
(
log-level
)
\
remote
\
--etherscan
.apikey.eth
$(ETHERSCAN_APIKEY_ETH)
\
--etherscan
.apikey.op
$(ETHERSCAN_APIKEY_OP)
mkdir
:
mkdir
-p
$(pkg)
...
...
op-bindings/artifacts.json
View file @
816e425c
...
...
@@ -46,5 +46,104 @@
"ISemver"
,
"StorageSetter"
,
"SuperchainConfig"
],
"remote"
:
[
{
"name"
:
"MultiCall3"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0xcA11bde05977b3631167028862bE2a173976CA11"
,
"op"
:
"0xcA11bde05977b3631167028862bE2a173976CA11"
}
},
{
"name"
:
"Create2Deployer"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0xF49600926c7109BD66Ab97a2c036bf696e58Dbc2"
}
},
{
"name"
:
"Safe_v130"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552"
,
"op"
:
"0x69f4D1788e39c87893C980c06EdF4b7f686e2938"
},
"deploymentSalt"
:
"0000000000000000000000000000000000000000000000000000000000000000"
},
{
"name"
:
"SafeL2_v130"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0x3E5c63644E683549055b9Be8653de26E0B4CD36E"
,
"op"
:
"0xfb1bffC9d739B8D520DaF37dF666da4C687191EA"
},
"deploymentSalt"
:
"0000000000000000000000000000000000000000000000000000000000000000"
},
{
"name"
:
"MultiSendCallOnly_v130"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0x40A2aCCbd92BCA938b02010E17A5b8929b49130D"
,
"op"
:
"0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B"
},
"deploymentSalt"
:
"0000000000000000000000000000000000000000000000000000000000000000"
},
{
"name"
:
"SafeSingletonFactory"
,
"verified"
:
false
,
"deployments"
:
{
"eth"
:
"0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7"
,
"op"
:
"0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7"
},
"abi"
:
"[{\"payable\"
:
true
,
\
"stateMutability\"
:
\
"payable\",\"type\"
:
\
"fallback\",\"inputs\"
:[{
\
"internalType\"
:
\
"bytes32\",\"name\"
:
\
"salt\",\"type\"
:
\
"bytes32\"},{\"internalType\"
:
\
"bytes32\",\"name\"
:
\
"creationCode\",\"type\"
:
\
"bytes
\"
}]}]"
},
{
"name"
:
"DeterministicDeploymentProxy"
,
"verified"
:
false
,
"deployments"
:
{
"eth"
:
"0x4e59b44847b379578588920cA78FbF26c0B4956C"
,
"op"
:
"0x4e59b44847b379578588920cA78FbF26c0B4956C"
},
"abi"
:
"[{\"payable\"
:
true
,
\
"stateMutability\"
:
\
"payable\",\"type\"
:
\
"fallback\",\"inputs\"
:[{
\
"internalType\"
:
\
"bytes32\",\"name\"
:
\
"salt\",\"type\"
:
\
"bytes32\"},{\"internalType\"
:
\
"bytes32\",\"name\"
:
\
"creationCode\",\"type\"
:
\
"bytes
\"
}]}]"
},
{
"name"
:
"MultiSend_v130"
,
"verified"
:
true
,
"deployments"
:
{
"op"
:
"0x998739BFdAAdde7C933B942a68053933098f9EDa"
},
"deploymentSalt"
:
"0000000000000000000000000000000000000000000000000000000000000000"
},
{
"name"
:
"Permit2"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0x000000000022D473030F116dDEE9F6B43aC78BA3"
,
"op"
:
"0x000000000022D473030F116dDEE9F6B43aC78BA3"
},
"deploymentSalt"
:
"0000000000000000000000000000000000000000d3af2663da51c10215000000"
,
"deployer"
:
"0x4e59b44847b379578588920cA78FbF26c0B4956C"
},
{
"name"
:
"SenderCreator"
,
"verified"
:
false
,
"deployments"
:
{
"eth"
:
"0x7fc98430eaedbb6070b35b39d798725049088348"
,
"op"
:
"0x7fc98430eaedbb6070b35b39d798725049088348"
},
"initBytecode"
:
"0x6080806040523461001657610210908161001c8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c63570e1a361461002857600080fd5b346100c95760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100c95760043567ffffffffffffffff918282116100c957366023830112156100c95781600401359283116100c95736602484840101116100c9576100c561009e84602485016100fc565b60405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b0390f35b80fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90806014116101bb5767ffffffffffffffff917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec82018381116101cd575b604051937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81600b8701160116850190858210908211176101c0575b604052808452602084019036848401116101bb576020946000600c819682946014880187378301015251923560601c5af19060005191156101b557565b60009150565b600080fd5b6101c86100cc565b610178565b6101d56100cc565b61013a56fea26469706673582212201927e80b76ab9b71c952137dd676621a9fdf520c25928815636594036eb1c40364736f6c63430008110033"
,
"abi"
:
"[{\"inputs\"
:
[{
\
"internalType\"
:
\
"bytes\",\"name\"
:
\
"initCode\",\"type\"
:
\
"bytes\"}],\"name\"
:
\
"createSender\",\"outputs\"
:
[{
\
"internalType\"
:
\
"address\",\"name\"
:
\
"sender\",\"type\"
:
\
"address\"}],\"stateMutability\"
:
\
"nonpayable\",\"type\"
:
\
"function
\"
}]"
},
{
"name"
:
"EntryPoint"
,
"verified"
:
true
,
"deployments"
:
{
"eth"
:
"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
,
"op"
:
"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
},
"deploymentSalt"
:
"0000000000000000000000000000000000000000000000000000000000000000"
}
]
}
op-bindings/bindgen/generator_remote.go
0 → 100644
View file @
816e425c
package
main
import
(
"context"
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
)
type
bindGenGeneratorRemote
struct
{
bindGenGeneratorBase
contractDataClients
struct
{
eth
contractDataClient
op
contractDataClient
}
tempArtifactsDir
string
}
type
contractDataClient
interface
{
FetchAbi
(
ctx
context
.
Context
,
address
string
)
(
string
,
error
)
FetchDeployedBytecode
(
ctx
context
.
Context
,
address
string
)
(
string
,
error
)
FetchDeploymentTxHash
(
ctx
context
.
Context
,
address
string
)
(
string
,
error
)
FetchDeploymentTx
(
ctx
context
.
Context
,
txHash
string
)
(
etherscan
.
TxInfo
,
error
)
}
type
deployments
struct
{
Eth
common
.
Address
`json:"eth"`
Op
common
.
Address
`json:"op"`
}
type
remoteContract
struct
{
Name
string
`json:"name"`
Verified
bool
`json:"verified"`
Deployments
deployments
`json:"deployments"`
DeploymentSalt
string
`json:"deploymentSalt"`
Deployer
common
.
Address
`json:"deployer"`
ABI
string
`json:"abi"`
InitBytecode
string
`json:"initBytecode"`
}
type
remoteContractMetadata
struct
{
remoteContract
Package
string
InitBin
string
DeployedBin
string
}
func
(
generator
*
bindGenGeneratorRemote
)
generateBindings
()
error
{
contracts
,
err
:=
readContractList
(
generator
.
logger
,
generator
.
contractsListPath
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error reading contract list %s: %w"
,
generator
.
contractsListPath
,
err
)
}
if
len
(
contracts
.
Remote
)
==
0
{
return
fmt
.
Errorf
(
"no contracts parsed from given contract list: %s"
,
generator
.
contractsListPath
)
}
return
generator
.
processContracts
(
contracts
.
Remote
)
}
func
(
generator
*
bindGenGeneratorRemote
)
processContracts
(
contracts
[]
remoteContract
)
error
{
var
err
error
generator
.
tempArtifactsDir
,
err
=
mkTempArtifactsDir
(
generator
.
logger
)
if
err
!=
nil
{
return
err
}
defer
func
()
{
err
:=
os
.
RemoveAll
(
generator
.
tempArtifactsDir
)
if
err
!=
nil
{
generator
.
logger
.
Error
(
"Error removing temporary artifact directory"
,
"path"
,
generator
.
tempArtifactsDir
,
"err"
,
err
.
Error
())
}
else
{
generator
.
logger
.
Debug
(
"Successfully removed temporary artifact directory"
)
}
}()
for
_
,
contract
:=
range
contracts
{
generator
.
logger
.
Info
(
"Generating bindings and metadata for remote contract"
,
"contract"
,
contract
.
Name
)
contractMetadata
:=
remoteContractMetadata
{
remoteContract
:
remoteContract
{
Name
:
contract
.
Name
,
Deployments
:
contract
.
Deployments
,
DeploymentSalt
:
contract
.
DeploymentSalt
,
ABI
:
contract
.
ABI
,
Verified
:
contract
.
Verified
,
},
Package
:
generator
.
bindingsPackageName
,
}
var
err
error
switch
contract
.
Name
{
case
"MultiCall3"
,
"Safe_v130"
,
"SafeL2_v130"
,
"MultiSendCallOnly_v130"
,
"EntryPoint"
,
"SafeSingletonFactory"
,
"DeterministicDeploymentProxy"
:
err
=
generator
.
standardHandler
(
&
contractMetadata
)
case
"Create2Deployer"
:
err
=
generator
.
create2DeployerHandler
(
&
contractMetadata
)
case
"MultiSend_v130"
:
err
=
generator
.
multiSendHandler
(
&
contractMetadata
)
case
"SenderCreator"
:
// The SenderCreator contract is deployed by EntryPoint, so the transaction data
// from the deployment transaction is for the entire EntryPoint deployment.
// So, we're manually providing the initialization bytecode
contractMetadata
.
InitBin
=
contract
.
InitBytecode
err
=
generator
.
senderCreatorHandler
(
&
contractMetadata
)
case
"Permit2"
:
// Permit2 has an immutable Solidity variable that resolves to block.chainid,
// so we can't use the deployed bytecode, and instead must generate it
// at some later point not handled by BindGen.
// DeployerAddress is intended to be used to help deploy Permit2 at it's deterministic address
// to a chain set with the required id to be able to obtain a diff minimized deployed bytecode
contractMetadata
.
Deployer
=
contract
.
Deployer
err
=
generator
.
permit2Handler
(
&
contractMetadata
)
default
:
err
=
fmt
.
Errorf
(
"unknown contract: %s, don't know how to handle it"
,
contract
.
Name
)
}
if
err
!=
nil
{
return
err
}
}
return
nil
}
op-bindings/bindgen/main.go
View file @
816e425c
...
...
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum-optimism/optimism/op-e2e/config"
oplog
"github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/log"
...
...
@@ -27,6 +28,12 @@ const (
// Local Contracts Flags
SourceMapsListFlagName
=
"source-maps-list"
ForgeArtifactsFlagName
=
"forge-artifacts"
// Remote Contracts Flags
EtherscanApiKeyEthFlagName
=
"etherscan.apikey.eth"
EtherscanApiKeyOpFlagName
=
"etherscan.apikey.op"
RpcUrlEthFlagName
=
"rpc.url.eth"
RpcUrlOpFlagName
=
"rpc.url.op"
)
func
main
()
{
...
...
@@ -41,12 +48,24 @@ func main() {
Usage
:
"Generate contract bindings"
,
Flags
:
baseFlags
(),
Subcommands
:
[]
*
cli
.
Command
{
{
Name
:
"all"
,
Usage
:
"Generate bindings for local and remote contracts"
,
Flags
:
append
(
localFlags
(),
remoteFlags
()
...
),
Action
:
generateBindings
,
},
{
Name
:
"local"
,
Usage
:
"Generate bindings for locally sourced contracts"
,
Flags
:
localFlags
(),
Action
:
generateBindings
,
},
{
Name
:
"remote"
,
Usage
:
"Generate bindings for remotely sourced contracts"
,
Flags
:
remoteFlags
(),
Action
:
generateBindings
,
},
},
},
},
...
...
@@ -67,6 +86,24 @@ func generateBindings(c *cli.Context) error {
logger
:=
setupLogger
(
c
)
switch
c
.
Command
.
Name
{
case
"all"
:
localBindingsGenerator
,
err
:=
parseConfigLocal
(
logger
,
c
)
if
err
!=
nil
{
return
err
}
if
err
:=
localBindingsGenerator
.
generateBindings
();
err
!=
nil
{
return
fmt
.
Errorf
(
"error generating local bindings: %w"
,
err
)
}
remoteBindingsGenerator
,
err
:=
parseConfigRemote
(
logger
,
c
)
if
err
!=
nil
{
return
err
}
if
err
:=
remoteBindingsGenerator
.
generateBindings
();
err
!=
nil
{
return
fmt
.
Errorf
(
"error generating remote bindings: %w"
,
err
)
}
return
nil
case
"local"
:
localBindingsGenerator
,
err
:=
parseConfigLocal
(
logger
,
c
)
if
err
!=
nil
{
...
...
@@ -76,6 +113,15 @@ func generateBindings(c *cli.Context) error {
return
fmt
.
Errorf
(
"error generating local bindings: %w"
,
err
)
}
return
nil
case
"remote"
:
remoteBindingsGenerator
,
err
:=
parseConfigRemote
(
logger
,
c
)
if
err
!=
nil
{
return
err
}
if
err
:=
remoteBindingsGenerator
.
generateBindings
();
err
!=
nil
{
return
fmt
.
Errorf
(
"error generating remote bindings: %w"
,
err
)
}
return
nil
default
:
return
fmt
.
Errorf
(
"unknown command: %s"
,
c
.
Command
.
Name
)
}
...
...
@@ -113,6 +159,20 @@ func parseConfigLocal(logger log.Logger, c *cli.Context) (bindGenGeneratorLocal,
},
nil
}
func
parseConfigRemote
(
logger
log
.
Logger
,
c
*
cli
.
Context
)
(
bindGenGeneratorRemote
,
error
)
{
baseConfig
,
err
:=
parseConfigBase
(
logger
,
c
)
if
err
!=
nil
{
return
bindGenGeneratorRemote
{},
err
}
generator
:=
bindGenGeneratorRemote
{
bindGenGeneratorBase
:
baseConfig
,
}
generator
.
contractDataClients
.
eth
=
etherscan
.
NewEthereumClient
(
c
.
String
(
EtherscanApiKeyEthFlagName
))
generator
.
contractDataClients
.
op
=
etherscan
.
NewOptimismClient
(
c
.
String
(
EtherscanApiKeyOpFlagName
))
return
generator
,
nil
}
func
baseFlags
()
[]
cli
.
Flag
{
baseFlags
:=
[]
cli
.
Flag
{
&
cli
.
StringFlag
{
...
...
@@ -148,3 +208,18 @@ func localFlags() []cli.Flag {
},
}
}
func
remoteFlags
()
[]
cli
.
Flag
{
return
[]
cli
.
Flag
{
&
cli
.
StringFlag
{
Name
:
EtherscanApiKeyEthFlagName
,
Usage
:
"API key to make queries to Etherscan for Ethereum"
,
Required
:
true
,
},
&
cli
.
StringFlag
{
Name
:
EtherscanApiKeyOpFlagName
,
Usage
:
"API key to make queries to Etherscan for Optimism"
,
Required
:
true
,
},
}
}
op-bindings/bindgen/remote_handlers.go
0 → 100644
View file @
816e425c
package
main
import
(
"context"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
)
type
contractData
struct
{
abi
string
deployedBin
string
deploymentTx
etherscan
.
TxInfo
}
func
(
generator
*
bindGenGeneratorRemote
)
standardHandler
(
contractMetadata
*
remoteContractMetadata
)
error
{
fetchedData
,
err
:=
generator
.
fetchContractData
(
contractMetadata
.
Verified
,
"eth"
,
contractMetadata
.
Deployments
.
Eth
.
Hex
())
if
err
!=
nil
{
return
err
}
contractMetadata
.
DeployedBin
=
fetchedData
.
deployedBin
// If ABI was explicitly provided by config, don't overwrite
if
contractMetadata
.
ABI
==
""
{
contractMetadata
.
ABI
=
fetchedData
.
abi
}
else
if
fetchedData
.
abi
!=
""
&&
contractMetadata
.
ABI
!=
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
)
}
if
contractMetadata
.
InitBin
,
err
=
generator
.
removeDeploymentSalt
(
fetchedData
.
deploymentTx
.
Input
,
contractMetadata
.
DeploymentSalt
);
err
!=
nil
{
return
err
}
if
err
:=
generator
.
compareBytecodeWithOp
(
contractMetadata
,
true
,
true
);
err
!=
nil
{
return
fmt
.
Errorf
(
"error comparing contract bytecode for %s: %w"
,
contractMetadata
.
Name
,
err
)
}
return
generator
.
writeAllOutputs
(
contractMetadata
,
remoteContractMetadataTemplate
)
}
func
(
generator
*
bindGenGeneratorRemote
)
create2DeployerHandler
(
contractMetadata
*
remoteContractMetadata
)
error
{
fetchedData
,
err
:=
generator
.
fetchContractData
(
contractMetadata
.
Verified
,
"eth"
,
contractMetadata
.
Deployments
.
Eth
.
Hex
())
if
err
!=
nil
{
return
err
}
contractMetadata
.
ABI
=
fetchedData
.
abi
contractMetadata
.
DeployedBin
=
fetchedData
.
deployedBin
if
contractMetadata
.
InitBin
,
err
=
generator
.
removeDeploymentSalt
(
fetchedData
.
deploymentTx
.
Input
,
contractMetadata
.
DeploymentSalt
);
err
!=
nil
{
return
err
}
// We're not comparing the bytecode for Create2Deployer with deployment on OP,
// because we're predeploying a modified version of Create2Deployer that has not yet been
// deployed to OP.
// For context: https://github.com/ethereum-optimism/op-geth/pull/126
return
generator
.
writeAllOutputs
(
contractMetadata
,
remoteContractMetadataTemplate
)
}
func
(
generator
*
bindGenGeneratorRemote
)
multiSendHandler
(
contractMetadata
*
remoteContractMetadata
)
error
{
// MultiSend has an immutable that resolves to this(address).
// Because we're predeploying MultiSend to the same address as on OP,
// we can use the deployed bytecode directly for the predeploy
fetchedData
,
err
:=
generator
.
fetchContractData
(
contractMetadata
.
Verified
,
"op"
,
contractMetadata
.
Deployments
.
Op
.
Hex
())
if
err
!=
nil
{
return
err
}
contractMetadata
.
ABI
=
fetchedData
.
abi
contractMetadata
.
DeployedBin
=
fetchedData
.
deployedBin
if
contractMetadata
.
InitBin
,
err
=
generator
.
removeDeploymentSalt
(
fetchedData
.
deploymentTx
.
Input
,
contractMetadata
.
DeploymentSalt
);
err
!=
nil
{
return
err
}
return
generator
.
writeAllOutputs
(
contractMetadata
,
remoteContractMetadataTemplate
)
}
func
(
generator
*
bindGenGeneratorRemote
)
senderCreatorHandler
(
contractMetadata
*
remoteContractMetadata
)
error
{
var
err
error
contractMetadata
.
DeployedBin
,
err
=
generator
.
contractDataClients
.
eth
.
FetchDeployedBytecode
(
context
.
Background
(),
contractMetadata
.
Deployments
.
Eth
.
Hex
())
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error fetching deployed bytecode: %w"
,
err
)
}
// The SenderCreator contract is deployed by EntryPoint, so the transaction data
// 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
if
err
:=
generator
.
compareBytecodeWithOp
(
contractMetadata
,
false
,
true
);
err
!=
nil
{
return
fmt
.
Errorf
(
"error comparing contract bytecode for %s: %w"
,
contractMetadata
.
Name
,
err
)
}
return
generator
.
writeAllOutputs
(
contractMetadata
,
remoteContractMetadataTemplate
)
}
func
(
generator
*
bindGenGeneratorRemote
)
permit2Handler
(
contractMetadata
*
remoteContractMetadata
)
error
{
fetchedData
,
err
:=
generator
.
fetchContractData
(
contractMetadata
.
Verified
,
"eth"
,
contractMetadata
.
Deployments
.
Eth
.
Hex
())
if
err
!=
nil
{
return
err
}
contractMetadata
.
ABI
=
fetchedData
.
abi
if
contractMetadata
.
InitBin
,
err
=
generator
.
removeDeploymentSalt
(
fetchedData
.
deploymentTx
.
Input
,
contractMetadata
.
DeploymentSalt
);
err
!=
nil
{
return
err
}
if
!
strings
.
EqualFold
(
contractMetadata
.
Deployer
.
Hex
(),
fetchedData
.
deploymentTx
.
To
)
{
return
fmt
.
Errorf
(
"expected deployer address: %s doesn't match the to address: %s for Permit2's proxy deployment transaction"
,
contractMetadata
.
Deployer
.
Hex
(),
fetchedData
.
deploymentTx
.
To
,
)
}
// We're not comparing deployed bytecode because Permit2 has immutable Solidity variables that
// are dependent on block.chainid
if
err
:=
generator
.
compareBytecodeWithOp
(
contractMetadata
,
true
,
false
);
err
!=
nil
{
return
fmt
.
Errorf
(
"error comparing contract bytecode for %s: %w"
,
contractMetadata
.
Name
,
err
)
}
return
generator
.
writeAllOutputs
(
contractMetadata
,
permit2MetadataTemplate
)
}
func
(
generator
*
bindGenGeneratorRemote
)
fetchContractData
(
contractVerified
bool
,
chain
,
deploymentAddress
string
)
(
contractData
,
error
)
{
var
data
contractData
var
err
error
var
client
contractDataClient
switch
chain
{
case
"eth"
:
client
=
generator
.
contractDataClients
.
eth
case
"op"
:
client
=
generator
.
contractDataClients
.
op
default
:
return
data
,
fmt
.
Errorf
(
"unknown chain, unable to retrieve a contract data client for chain: %s"
,
chain
)
}
if
contractVerified
{
data
.
abi
,
err
=
client
.
FetchAbi
(
context
.
Background
(),
deploymentAddress
)
if
err
!=
nil
{
return
contractData
{},
fmt
.
Errorf
(
"error fetching ABI: %w"
,
err
)
}
}
data
.
deployedBin
,
err
=
client
.
FetchDeployedBytecode
(
context
.
Background
(),
deploymentAddress
)
if
err
!=
nil
{
return
contractData
{},
fmt
.
Errorf
(
"error fetching deployed bytecode: %w"
,
err
)
}
deploymentTxHash
,
err
:=
client
.
FetchDeploymentTxHash
(
context
.
Background
(),
deploymentAddress
)
if
err
!=
nil
{
return
contractData
{},
fmt
.
Errorf
(
"error fetching deployment transaction hash: %w"
,
err
)
}
data
.
deploymentTx
,
err
=
client
.
FetchDeploymentTx
(
context
.
Background
(),
deploymentTxHash
)
if
err
!=
nil
{
return
contractData
{},
fmt
.
Errorf
(
"error fetching deployment transaction data: %w"
,
err
)
}
return
data
,
nil
}
func
(
generator
*
bindGenGeneratorRemote
)
removeDeploymentSalt
(
deploymentData
,
deploymentSalt
string
)
(
string
,
error
)
{
if
deploymentSalt
==
""
{
return
deploymentData
,
nil
}
re
,
err
:=
regexp
.
Compile
(
fmt
.
Sprintf
(
"^0x(%s)"
,
deploymentSalt
))
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to compile regular expression: %w"
,
err
)
}
if
!
re
.
MatchString
(
deploymentData
)
{
return
""
,
fmt
.
Errorf
(
"expected salt: %s to be at the beginning of the contract initialization code: %s, but it wasn't"
,
deploymentSalt
,
deploymentData
,
)
}
return
re
.
ReplaceAllString
(
deploymentData
,
""
),
nil
}
func
(
generator
*
bindGenGeneratorRemote
)
compareBytecodeWithOp
(
contractMetadataEth
*
remoteContractMetadata
,
compareInitialization
,
compareDeployment
bool
)
error
{
// 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
())
if
err
!=
nil
{
return
err
}
if
compareInitialization
{
if
opContractData
.
deploymentTx
.
Input
,
err
=
generator
.
removeDeploymentSalt
(
opContractData
.
deploymentTx
.
Input
,
contractMetadataEth
.
DeploymentSalt
);
err
!=
nil
{
return
err
}
if
!
strings
.
EqualFold
(
contractMetadataEth
.
InitBin
,
opContractData
.
deploymentTx
.
Input
)
{
return
fmt
.
Errorf
(
"initialization bytecode on Ethereum doesn't match bytecode on Optimism. contract=%s bytecodeEth=%s bytecodeOp=%s"
,
contractMetadataEth
.
Name
,
contractMetadataEth
.
InitBin
,
opContractData
.
deploymentTx
.
Input
,
)
}
}
if
compareDeployment
{
if
!
strings
.
EqualFold
(
contractMetadataEth
.
DeployedBin
,
opContractData
.
deployedBin
)
{
return
fmt
.
Errorf
(
"deployed bytecode on Ethereum doesn't match bytecode on Optimism. contract=%s bytecodeEth=%s bytecodeOp=%s"
,
contractMetadataEth
.
Name
,
contractMetadataEth
.
DeployedBin
,
opContractData
.
deployedBin
,
)
}
}
return
nil
}
func
(
generator
*
bindGenGeneratorRemote
)
writeAllOutputs
(
contractMetadata
*
remoteContractMetadata
,
fileTemplate
string
)
error
{
abiFilePath
,
bytecodeFilePath
,
err
:=
writeContractArtifacts
(
generator
.
logger
,
generator
.
tempArtifactsDir
,
contractMetadata
.
Name
,
[]
byte
(
contractMetadata
.
ABI
),
[]
byte
(
contractMetadata
.
InitBin
),
)
if
err
!=
nil
{
return
err
}
err
=
genContractBindings
(
generator
.
logger
,
abiFilePath
,
bytecodeFilePath
,
generator
.
bindingsPackageName
,
contractMetadata
.
Name
)
if
err
!=
nil
{
return
err
}
return
generator
.
writeContractMetadata
(
contractMetadata
,
template
.
Must
(
template
.
New
(
"remoteContractMetadata"
)
.
Parse
(
fileTemplate
)),
)
}
func
(
generator
*
bindGenGeneratorRemote
)
writeContractMetadata
(
contractMetadata
*
remoteContractMetadata
,
fileTemplate
*
template
.
Template
)
error
{
metadataFilePath
:=
filepath
.
Join
(
generator
.
metadataOut
,
strings
.
ToLower
(
contractMetadata
.
Name
)
+
"_more.go"
)
metadataFile
,
err
:=
os
.
OpenFile
(
metadataFilePath
,
os
.
O_RDWR
|
os
.
O_CREATE
|
os
.
O_TRUNC
,
0
o600
,
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error opening %s's metadata file at %s: %w"
,
contractMetadata
.
Name
,
metadataFilePath
,
err
)
}
defer
metadataFile
.
Close
()
if
err
:=
fileTemplate
.
Execute
(
metadataFile
,
contractMetadata
);
err
!=
nil
{
return
fmt
.
Errorf
(
"error writing %s's contract metadata at %s: %w"
,
contractMetadata
.
Name
,
metadataFilePath
,
err
)
}
generator
.
logger
.
Debug
(
"Successfully wrote contract metadata"
,
"contract"
,
contractMetadata
.
Name
,
"path"
,
metadataFilePath
)
return
nil
}
// remoteContractMetadataTemplate is a Go text template for generating the metadata
// associated with a remotely sourced contracts.
//
// The template expects the following data to be provided:
// - .Package: the name of the Go package.
// - .Name: the name of the contract.
// - .DeployedBin: the binary (hex-encoded) of the deployed contract.
var
remoteContractMetadataTemplate
=
`// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package {{.Package}}
var {{.Name}}DeployedBin = "{{.DeployedBin}}"
func init() {
deployedBytecodes["{{.Name}}"] = {{.Name}}DeployedBin
}
`
// permit2MetadataTemplate is a Go text template used to generate metadata
// for remotely sourced Permit2 contract. Because Permit2 has an immutable
// Solidity variables that depends on block.chainid, we can't use the deployed
// bytecode, but instead need to generate it specifically for each chain.
// To help with this, the metadata contains the initialization bytecode, the
// deployer address, and the CREATE2 salt, so that deployment can be
// replicated as closely as possible.
//
// The template expects the following data to be provided:
// - .Package: the name of the Go package.
// - .Name: the name of the contract.
// - .InitBin: the binary (hex-encoded) of the contract's initialization code.
// - .DeploymentSalt: the salt used during the contract's deployment.
// - .Deployer: the Ethereum address of the contract's deployer.
var
permit2MetadataTemplate
=
`// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package {{.Package}}
var {{.Name}}InitBin = "{{.InitBin}}"
var {{.Name}}DeploymentSalt = "{{.DeploymentSalt}}"
var {{.Name}}Deployer = "{{.Deployer}}"
func init() {
initBytecodes["{{.Name}}"] = {{.Name}}InitBin
deploymentSalts["{{.Name}}"] = {{.Name}}DeploymentSalt
deployers["{{.Name}}"] = {{.Name}}Deployer
}
`
op-bindings/bindgen/utils.go
View file @
816e425c
...
...
@@ -12,7 +12,8 @@ import (
)
type
contractsList
struct
{
Local
[]
string
`json:"local"`
Local
[]
string
`json:"local"`
Remote
[]
remoteContract
`json:"remote"`
}
// readContractList reads a JSON file from the given `filePath` and unmarshals
...
...
op-bindings/etherscan/client.go
View file @
816e425c
...
...
@@ -120,10 +120,7 @@ func (c *client) fetchEtherscanRpc(ctx context.Context, url string) (rpcResponse
}
var
resultString
string
err
=
json
.
Unmarshal
(
response
.
Result
,
&
resultString
)
if
err
!=
nil
{
return
rpcResponse
{},
fmt
.
Errorf
(
"failed to unmarshal response.Result as a string: %w"
,
err
)
}
_
=
json
.
Unmarshal
(
response
.
Result
,
&
resultString
)
if
resultString
==
errRateLimited
{
return
rpcResponse
{},
errors
.
New
(
errRateLimited
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment