-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2db4509
commit 5d642dc
Showing
5 changed files
with
235 additions
and
90 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package validation | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/ethereum-optimism/superchain-registry/superchain" | ||
"github.com/ethereum/go-ethereum" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/ethclient" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func testGasToken(t *testing.T, chain *superchain.ChainConfig) { | ||
l1Client, err := ethclient.Dial(superchain.Superchains[chain.Superchain].Config.L1.PublicRPC) | ||
require.NoError(t, err, "Failed to connect to the Ethereum client at RPC url %s", chain.PublicRPC) | ||
defer l1Client.Close() | ||
|
||
err = CheckGasToken(chain, l1Client) | ||
require.NoError(t, err) | ||
} | ||
|
||
func CheckGasToken(chain *superchain.ChainConfig, l1Client *ethclient.Client) error { | ||
l2Client, err := ethclient.Dial(chain.PublicRPC) | ||
if err != nil { | ||
return err | ||
} | ||
defer l2Client.Close() | ||
|
||
weth9PredeployAddress := superchain.MustHexToAddress("0x4200000000000000000000000000000000000006") | ||
want := "0000000000000000000000000000000000000000000000000000000000000020" + // offset | ||
"000000000000000000000000000000000000000000000000000000000000000d" + // length | ||
"5772617070656420457468657200000000000000000000000000000000000000" // "Wrapped Ether" padded to 32 bytes | ||
gotName, err := getHexString("WETH9.name()", weth9PredeployAddress, l2Client) | ||
if err != nil { | ||
return err | ||
} | ||
if want != gotName { | ||
return fmt.Errorf("predeploy WETH9.name(): want=%s, got=%s", want, gotName) | ||
} | ||
|
||
l1BlockPredeployAddress := superchain.MustHexToAddress("0x4200000000000000000000000000000000000015") | ||
got, err := getBool("isCustomGasToken()", l1BlockPredeployAddress, l2Client) | ||
if err != nil && !strings.Contains(err.Error(), "execution reverted") { | ||
// Pre: reverting is acceptable | ||
return err | ||
} else { | ||
// Post: must be set to false | ||
if got != false { | ||
return fmt.Errorf("L1Block.isCustomGasToken() must return false") | ||
} | ||
} | ||
|
||
got, err = getBool("isCustomGasToken()", superchain.Addresses[chain.ChainID].SystemConfigProxy, l2Client) | ||
if err != nil && !strings.Contains(err.Error(), "execution reverted") { | ||
// Pre: reverting is acceptable | ||
return err | ||
} else { | ||
// Post: must be set to false | ||
if got != false { | ||
return fmt.Errorf("SystemConfigProxy.isCustomGasToken() must return false") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func getBytes(method string, contractAddress superchain.Address, client EthClient) ([]byte, error) { | ||
addr := (common.Address(contractAddress)) | ||
callMsg := ethereum.CallMsg{ | ||
To: &addr, | ||
Data: crypto.Keccak256([]byte(method))[:4], | ||
} | ||
|
||
callContract := func(msg ethereum.CallMsg) ([]byte, error) { | ||
return client.CallContract(context.Background(), msg, nil) | ||
} | ||
|
||
return Retry(callContract)(callMsg) | ||
} | ||
|
||
func getHexString(method string, contractAddress superchain.Address, client EthClient) (string, error) { | ||
result, err := getBytes(method, contractAddress, client) | ||
return common.Bytes2Hex(result), err | ||
} | ||
|
||
func getBool(method string, contractAddress superchain.Address, client EthClient) (bool, error) { | ||
result, err := getBytes(method, contractAddress, client) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
switch common.HexToHash(string(result)) { | ||
case common.Hash{1}: | ||
return true, nil | ||
case common.Hash{}: | ||
return false, nil | ||
default: | ||
return false, errors.New("unexpected non-bool return value") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package validation | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/ethereum-optimism/superchain-registry/superchain" | ||
"github.com/ethereum-optimism/superchain-registry/validation/testutils" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGetBytes_Success(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Responses: map[string][]byte{ | ||
string(testutils.MethodID("myMethod()")): {0xde, 0xad, 0xbe, 0xef}, | ||
}, | ||
} | ||
contractAddress := superchain.MustHexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
result, err := getBytes("myMethod()", contractAddress, mockClient) | ||
require.NoError(t, err) | ||
require.Equal(t, []byte{0xde, 0xad, 0xbe, 0xef}, result) | ||
} | ||
|
||
func TestGetBytes_Error(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Err: errors.New("some call error"), | ||
} | ||
contractAddress := superchain.MustHexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
_, err := getBytes("failingMethod()", contractAddress, mockClient) | ||
require.Error(t, err) | ||
require.Contains(t, err.Error(), "some call error") | ||
} | ||
|
||
func TestGetHexString_Success(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Responses: map[string][]byte{ | ||
string(testutils.MethodID("hexMethod()")): {0x00, 0x11, 0x22, 0x33}, | ||
}, | ||
} | ||
contractAddress := superchain.MustHexToAddress("0xabcdef7890abcdef1234567890abcdef12345678") | ||
hexVal, err := getHexString("hexMethod()", contractAddress, mockClient) | ||
require.NoError(t, err) | ||
require.Equal(t, "00112233", hexVal) | ||
} | ||
|
||
func TestGetHexString_Error(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Err: errors.New("getHexString error"), | ||
} | ||
contractAddress := superchain.MustHexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
_, err := getHexString("hexMethod()", contractAddress, mockClient) | ||
require.Error(t, err) | ||
require.Contains(t, err.Error(), "getHexString error") | ||
} | ||
|
||
func TestGetBool_True(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Responses: map[string][]byte{ | ||
string(testutils.MethodID("boolMethod()")): []byte("0x0100000000000000000000000000000000000000000000000000000000000000"), | ||
}, | ||
} | ||
contractAddress := superchain.MustHexToAddress("0x1111117890abcdef1234567890abcdef12345678") | ||
val, err := getBool("boolMethod()", contractAddress, mockClient) | ||
require.NoError(t, err) | ||
require.True(t, val) | ||
} | ||
|
||
func TestGetBool_False(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Responses: map[string][]byte{ | ||
string(testutils.MethodID("boolMethod()")): []byte(""), | ||
}, | ||
} | ||
contractAddress := superchain.MustHexToAddress("0x2222227890abcdef1234567890abcdef12345678") | ||
val, err := getBool("boolMethod()", contractAddress, mockClient) | ||
require.NoError(t, err) | ||
require.False(t, val) | ||
} | ||
|
||
func TestGetBool_ErrorUnexpectedValue(t *testing.T) { | ||
t.Parallel() | ||
mockClient := &testutils.MockEthClient{ | ||
Responses: map[string][]byte{ | ||
string(testutils.MethodID("boolMethod()")): []byte("0xabcdef"), | ||
}, | ||
} | ||
contractAddress := superchain.MustHexToAddress("0x2222227890abcdef1234567890abcdef12345678") | ||
_, err := getBool("boolMethod()", contractAddress, mockClient) | ||
require.Error(t, err) | ||
require.Contains(t, err.Error(), "unexpected non-bool return value") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package testutils | ||
|
||
import ( | ||
"context" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
) | ||
|
||
// MockEthClient is a mock that implements EthCaller for testing. | ||
type MockEthClient struct { | ||
// Setup response maps keyed by method 4-byte signature + address, or | ||
// just by method signature if that's simpler for your tests. | ||
Responses map[string][]byte | ||
Err error | ||
} | ||
|
||
func (m *MockEthClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { | ||
if m.Err != nil { | ||
return nil, m.Err | ||
} | ||
return m.Responses[string(msg.Data)], nil | ||
} | ||
|
||
// Helper to get the 4-byte method ID (like what getBytes does internally) | ||
func MethodID(method string) []byte { | ||
return crypto.Keccak256([]byte(method))[:4] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters