Commit 58f74b1d authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

Introduce fast dispute game type (#10715)

* Introduce fast dispute game type

Avoids the need to change configuration to support fast withdrawals via fault proofs.

* e2e: Wait for game to become resolvable.

* Update kontrol snapshots.

* e2e: Set correct game type for proposer.

* challenger: Fast games are alphabet vm, not cannon.

* Set fast game clock duration to 0.

* Update snapshots again

* Use game type consistently.
parent f41e8f1e
......@@ -132,8 +132,6 @@ def init_devnet_l1_deploy_config(paths, update_timestamp=False):
deploy_config['l1GenesisBlockTimestamp'] = '{:#x}'.format(int(time.time()))
if DEVNET_FPAC:
deploy_config['useFaultProofs'] = True
deploy_config['faultGameMaxClockDuration'] = 10
deploy_config['faultGameWithdrawalDelay'] = 0
if DEVNET_PLASMA:
deploy_config['usePlasma'] = True
if GENERIC_PLASMA:
......@@ -269,7 +267,7 @@ def devnet_deploy(paths):
# Must be done selectively because op-proposer throws if both are set.
if DEVNET_FPAC:
docker_env['DGF_ADDRESS'] = dispute_game_factory
docker_env['DG_TYPE'] = '0'
docker_env['DG_TYPE'] = '254'
docker_env['PROPOSAL_INTERVAL'] = '10s'
else:
docker_env['L2OO_ADDRESS'] = l2_output_oracle
......
......@@ -54,12 +54,13 @@ type TraceType string
const (
TraceTypeAlphabet TraceType = "alphabet"
TraceTypeFast TraceType = "fast"
TraceTypeCannon TraceType = "cannon"
TraceTypeAsterisc TraceType = "asterisc"
TraceTypePermissioned TraceType = "permissioned"
)
var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon, TraceTypePermissioned, TraceTypeAsterisc}
var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon, TraceTypePermissioned, TraceTypeAsterisc, TraceTypeFast}
func (t TraceType) String() string {
return string(t)
......
......@@ -398,7 +398,7 @@ func TestRequireConfigForMultipleTraceTypesForCannonAndAsterisc(t *testing.T) {
cfg := validConfig(TraceTypeCannon)
applyValidConfigForAsterisc(&cfg)
cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAsterisc, TraceTypeAlphabet}
cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAsterisc, TraceTypeAlphabet, TraceTypeFast}
// Set all required options and check its valid
cfg.RollupRpc = validRollupRpc
require.NoError(t, cfg.Check())
......
......@@ -346,7 +346,7 @@ func CheckRequired(ctx *cli.Context, traceTypes []config.TraceType) error {
if err := CheckAsteriscFlags(ctx); err != nil {
return err
}
case config.TraceTypeAlphabet:
case config.TraceTypeAlphabet, config.TraceTypeFast:
default:
return fmt.Errorf("invalid trace type. must be one of %v", config.TraceTypes)
}
......
......@@ -88,8 +88,13 @@ func RegisterGameTypes(
return nil, fmt.Errorf("failed to register asterisc game type: %w", err)
}
}
if cfg.TraceTypeEnabled(config.TraceTypeFast) {
if err := registerAlphabet(faultTypes.FastGameType, registry, oracles, ctx, systemClock, l1Clock, logger, m, syncValidator, rollupClient, l2Client, txSender, gameFactory, caller, l1HeaderSource, selective, claimants); err != nil {
return nil, fmt.Errorf("failed to register fast game type: %w", err)
}
}
if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) {
if err := registerAlphabet(registry, oracles, ctx, systemClock, l1Clock, logger, m, syncValidator, rollupClient, l2Client, txSender, gameFactory, caller, l1HeaderSource, selective, claimants); err != nil {
if err := registerAlphabet(faultTypes.AlphabetGameType, registry, oracles, ctx, systemClock, l1Clock, logger, m, syncValidator, rollupClient, l2Client, txSender, gameFactory, caller, l1HeaderSource, selective, claimants); err != nil {
return nil, fmt.Errorf("failed to register alphabet game type: %w", err)
}
}
......@@ -97,6 +102,7 @@ func RegisterGameTypes(
}
func registerAlphabet(
gameType uint32,
registry Registry,
oracles OracleRegistry,
ctx context.Context,
......@@ -148,16 +154,16 @@ func registerAlphabet(
startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider)
return NewGamePlayer(ctx, systemClock, l1Clock, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants)
}
err := registerOracle(ctx, m, oracles, gameFactory, caller, faultTypes.AlphabetGameType)
err := registerOracle(ctx, m, oracles, gameFactory, caller, gameType)
if err != nil {
return err
}
registry.RegisterGameType(faultTypes.AlphabetGameType, playerCreator)
registry.RegisterGameType(gameType, playerCreator)
contractCreator := func(game types.GameMetadata) (claims.BondContract, error) {
return contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
}
registry.RegisterBondContract(faultTypes.AlphabetGameType, contractCreator)
registry.RegisterBondContract(gameType, contractCreator)
return nil
}
......
......@@ -22,6 +22,7 @@ const (
CannonGameType uint32 = 0
PermissionedGameType uint32 = 1
AsteriscGameType uint32 = 2
FastGameType uint32 = 254
AlphabetGameType uint32 = 255
)
......
......@@ -57,10 +57,14 @@ func RunProposerTest(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
var proposer *L2Proposer
if e2eutils.UseFPAC() {
optimismPortal2Contract, err := bindingspreview.NewOptimismPortal2(sd.DeploymentsL1.OptimismPortalProxy, miner.EthClient())
require.NoError(t, err)
respectedGameType, err := optimismPortal2Contract.RespectedGameType(&bind.CallOpts{})
require.NoError(t, err)
proposer = NewL2Proposer(t, log, &ProposerCfg{
DisputeGameFactoryAddr: &sd.DeploymentsL1.DisputeGameFactoryProxy,
ProposalInterval: 6 * time.Second,
DisputeGameType: 0,
DisputeGameType: respectedGameType,
ProposerKey: dp.Secrets.Proposer,
AllowNonFinalized: true,
}, miner.EthClient(), rollupSeqCl)
......
package actions
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
......@@ -8,6 +9,10 @@ import (
"math/rand"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
......@@ -450,7 +455,7 @@ func (s *CrossLayerUser) getLatestWithdrawalParams(t Testing) (*withdrawals.Prov
return &params, nil
}
func (s *CrossLayerUser) getDisputeGame(t Testing, params withdrawals.ProvenWithdrawalParameters) (*legacybindings.FaultDisputeGame, error) {
func (s *CrossLayerUser) getDisputeGame(t Testing, params withdrawals.ProvenWithdrawalParameters) (*legacybindings.FaultDisputeGame, common.Address, error) {
wd := crossdomain.Withdrawal{
Nonce: params.Nonce,
Sender: &params.Sender,
......@@ -473,7 +478,7 @@ func (s *CrossLayerUser) getDisputeGame(t Testing, params withdrawals.ProvenWith
proxy, err := legacybindings.NewFaultDisputeGame(game.DisputeGameProxy, s.L1.env.EthCl)
require.Nil(t, err)
return proxy, nil
return proxy, game.DisputeGameProxy, nil
}
// ActCompleteWithdrawal creates a L1 proveWithdrawal tx for latest withdrawal.
......@@ -562,13 +567,21 @@ func (s *CrossLayerUser) ResolveClaim(t Testing, l2TxHash common.Hash) common.Ha
return common.Hash{}
}
game, err := s.getDisputeGame(t, *params)
game, gameAddr, err := s.getDisputeGame(t, *params)
require.NoError(t, err)
expiry, err := game.MaxClockDuration(&bind.CallOpts{})
caller := batching.NewMultiCaller(s.L1.env.EthCl.Client(), batching.DefaultBatchSize)
gameContract, err := contracts.NewFaultDisputeGameContract(context.Background(), metrics.NoopContractMetrics, gameAddr, caller)
require.Nil(t, err)
time.Sleep(time.Duration(expiry) * time.Second)
timedCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
require.NoError(t, wait.For(timedCtx, time.Second, func() (bool, error) {
err := gameContract.CallResolveClaim(context.Background(), 0)
t.Logf("Could not resolve dispute game claim: %v", err)
return err == nil, nil
}))
resolveClaimTx, err := game.ResolveClaim(&s.L1.txOpts, common.Big0, common.Big0)
require.Nil(t, err)
......@@ -592,7 +605,7 @@ func (s *CrossLayerUser) Resolve(t Testing, l2TxHash common.Hash) common.Hash {
return common.Hash{}
}
game, err := s.getDisputeGame(t, *params)
game, _, err := s.getDisputeGame(t, *params)
require.NoError(t, err)
resolveTx, err := game.Resolve(&s.L1.txOpts)
......
......@@ -6,6 +6,8 @@ import (
"testing"
"time"
bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
......@@ -135,10 +137,14 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) {
var proposer *L2Proposer
if e2eutils.UseFPAC() {
optimismPortal2Contract, err := bindingspreview.NewOptimismPortal2(sd.DeploymentsL1.OptimismPortalProxy, miner.EthClient())
require.NoError(t, err)
respectedGameType, err := optimismPortal2Contract.RespectedGameType(&bind.CallOpts{})
require.NoError(t, err)
proposer = NewL2Proposer(t, log, &ProposerCfg{
DisputeGameFactoryAddr: &sd.DeploymentsL1.DisputeGameFactoryProxy,
ProposalInterval: 6 * time.Second,
DisputeGameType: 0,
DisputeGameType: respectedGameType,
ProposerKey: dp.Secrets.Proposer,
AllowNonFinalized: true,
}, miner.EthClient(), seq.RollupClient())
......
......@@ -133,6 +133,12 @@ func WithAlphabet() Option {
}
}
func WithFastGames() Option {
return func(c *config.Config) {
c.TraceTypes = append(c.TraceTypes, config.TraceTypeFast)
}
}
func NewChallenger(t *testing.T, ctx context.Context, sys EndpointProvider, name string, options ...Option) *Helper {
log := testlog.Logger(t, log.LevelDebug).New("role", name)
log.Info("Creating challenger")
......
......@@ -303,7 +303,7 @@ func TestHighestActedL1BlockMetric(t *testing.T) {
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
honestChallenger := disputeGameFactory.StartChallenger(ctx, "Honest", challenger.WithAlphabet(), challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
honestChallenger := disputeGameFactory.StartChallenger(ctx, "Honest", challenger.WithAlphabet(), challenger.WithFastGames(), challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
game1 := disputeGameFactory.StartOutputAlphabetGame(ctx, "sequencer", 1, common.Hash{0xaa})
sys.AdvanceTime(game1.MaxClockDuration(ctx))
......
......@@ -782,7 +782,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
DGFAddress: config.L1Deployments.DisputeGameFactoryProxy.Hex(),
ProposalInterval: 6 * time.Second,
DisputeGameType: 0,
DisputeGameType: 254, // Fast game type
PollInterval: 50 * time.Millisecond,
TxMgrConfig: newTxMgrConfig(sys.EthInstances["l1"].WSEndpoint(), cfg.Secrets.Proposer),
AllowNonFinalized: cfg.NonFinalizedProposals,
......
......@@ -659,7 +659,7 @@ func TestMixedWithdrawalValidity(t *testing.T) {
// Start a challenger to resolve claims and games once the clock expires
factoryHelper := disputegame.NewFactoryHelper(t, ctx, sys)
factoryHelper.StartChallenger(ctx, "Challenger",
challenger.WithCannon(t, sys.RollupConfig, sys.L2GenesisCfg),
challenger.WithFastGames(),
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
}
receipt, err = wait.ForReceiptOK(ctx, l1Client, tx.Hash())
......
......@@ -8,6 +8,8 @@ import (
"time"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
......@@ -17,6 +19,7 @@ import (
bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum-optimism/optimism/op-service/predeploys"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
......@@ -201,10 +204,18 @@ func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Clie
proxy, err := legacybindings.NewFaultDisputeGame(game.DisputeGameProxy, l1Client)
require.Nil(t, err)
expiry, err := proxy.MaxClockDuration(&bind.CallOpts{})
caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize)
gameContract, err := contracts.NewFaultDisputeGameContract(context.Background(), metrics.NoopContractMetrics, game.DisputeGameProxy, caller)
require.Nil(t, err)
time.Sleep(time.Duration(expiry) * time.Second)
timedCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
require.NoError(t, wait.For(timedCtx, time.Second, func() (bool, error) {
err := gameContract.CallResolveClaim(context.Background(), 0)
t.Logf("Could not resolve dispute game claim: %v", err)
return err == nil, nil
}))
resolveClaimTx, err := proxy.ResolveClaim(opts, common.Big0, common.Big0)
require.Nil(t, err)
......
......@@ -178,7 +178,7 @@ services:
# Note: this will need to be updated to point to a L1 consensus node when there is one in the devnet
OP_CHALLENGER_L1_BEACON: "unset"
OP_CHALLENGER_ROLLUP_RPC: http://op-node:8545
OP_CHALLENGER_TRACE_TYPE: cannon
OP_CHALLENGER_TRACE_TYPE: cannon,fast
OP_CHALLENGER_GAME_FACTORY_ADDRESS: ${DGF_ADDRESS}
# The devnet can't set the absolute prestate output root because the contracts are deployed in L1 genesis
# before the L2 genesis is known.
......
......@@ -63,7 +63,7 @@
"preimageOracleChallengePeriod": 120,
"proofMaturityDelaySeconds": 12,
"disputeGameFinalityDelaySeconds": 6,
"respectedGameType": 0,
"respectedGameType": 254,
"useFaultProofs": false,
"usePlasma": false,
"daCommitmentType": "KeccakCommitment",
......
......@@ -80,6 +80,7 @@ contract Deploy is Deployer {
Claim absolutePrestate;
IBigStepper faultVm;
uint256 maxGameDepth;
Duration maxClockDuration;
}
////////////////////////////////////////////////////////////////
......@@ -343,6 +344,7 @@ contract Deploy is Deployer {
initializeImplementations();
setAlphabetFaultGameImplementation({ _allowUpgrade: false });
setFastFaultGameImplementation({ _allowUpgrade: false });
setCannonFaultGameImplementation({ _allowUpgrade: false });
setPermissionedCannonFaultGameImplementation({ _allowUpgrade: false });
......@@ -361,9 +363,9 @@ contract Deploy is Deployer {
deployERC1967Proxy("OptimismMintableERC20FactoryProxy");
deployERC1967Proxy("L1ERC721BridgeProxy");
// Both the DisputeGameFactory and L2OutputOracle proxies are deployed regardles of whether FPAC is enabled
// to prevent a nastier refactor to the deploy scripts. In the future, the L2OutputOracle will be removed. If
// fault proofs are not enabled, the DisputeGameFactory proxy will be unused.
// Both the DisputeGameFactory and L2OutputOracle proxies are deployed regardless of whether fault proofs is
// enabled to prevent a nastier refactor to the deploy scripts. In the future, the L2OutputOracle will be
// removed. If fault proofs are not enabled, the DisputeGameFactory proxy will be unused.
deployERC1967Proxy("DisputeGameFactoryProxy");
deployERC1967Proxy("L2OutputOracleProxy");
deployERC1967Proxy("DelayedWETHProxy");
......@@ -396,10 +398,9 @@ contract Deploy is Deployer {
function initializeImplementations() public {
console.log("Initializing implementations");
// Selectively initialize either the original OptimismPortal or the new OptimismPortal2. Since this will upgrade
// the proxy, we cannot initialize both. FPAC warning can be removed once we're done with the old OptimismPortal
// contract.
// the proxy, we cannot initialize both.
if (cfg.useFaultProofs()) {
console.log("WARNING: FPAC is enabled. Initializing the OptimismPortal proxy with the OptimismPortal2.");
console.log("Fault proofs enabled. Initializing the OptimismPortal proxy with the OptimismPortal2.");
initializeOptimismPortal2();
} else {
initializeOptimismPortal();
......@@ -956,7 +957,7 @@ contract Deploy is Deployer {
address anchorStateRegistryProxy = mustGetAddress("AnchorStateRegistryProxy");
address anchorStateRegistry = mustGetAddress("AnchorStateRegistry");
AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](4);
AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](5);
roots[0] = AnchorStateRegistry.StartingAnchorRoot({
gameType: GameTypes.CANNON,
outputRoot: OutputRoot({
......@@ -985,6 +986,13 @@ contract Deploy is Deployer {
l2BlockNumber: cfg.faultGameGenesisBlock()
})
});
roots[4] = AnchorStateRegistry.StartingAnchorRoot({
gameType: GameTypes.FAST,
outputRoot: OutputRoot({
root: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
l2BlockNumber: cfg.faultGameGenesisBlock()
})
});
_upgradeAndCallViaSafe({
_proxy: payable(anchorStateRegistryProxy),
......@@ -1376,7 +1384,8 @@ contract Deploy is Deployer {
gameType: GameTypes.CANNON,
absolutePrestate: loadMipsAbsolutePrestate(),
faultVm: IBigStepper(mustGetAddress("Mips")),
maxGameDepth: cfg.faultGameMaxDepth()
maxGameDepth: cfg.faultGameMaxDepth(),
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration()))
})
});
}
......@@ -1397,7 +1406,8 @@ contract Deploy is Deployer {
gameType: GameTypes.PERMISSIONED_CANNON,
absolutePrestate: loadMipsAbsolutePrestate(),
faultVm: IBigStepper(mustGetAddress("Mips")),
maxGameDepth: cfg.faultGameMaxDepth()
maxGameDepth: cfg.faultGameMaxDepth(),
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration()))
})
});
}
......@@ -1419,11 +1429,35 @@ contract Deploy is Deployer {
absolutePrestate: outputAbsolutePrestate,
faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, PreimageOracle(mustGetAddress("PreimageOracle")))),
// The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive.
maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1
maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1,
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration()))
})
});
}
/// @notice Sets the implementation for the `ALPHABET` game type in the `DisputeGameFactory`
function setFastFaultGameImplementation(bool _allowUpgrade) public onlyDevnet broadcast {
console.log("Setting Fast FaultDisputeGame implementation");
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
DelayedWETH weth = DelayedWETH(mustGetAddress("DelayedWETHProxy"));
Claim outputAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
_setFaultGameImplementation({
_factory: factory,
_allowUpgrade: _allowUpgrade,
_params: FaultDisputeGameParams({
anchorStateRegistry: AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.FAST,
absolutePrestate: outputAbsolutePrestate,
faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, PreimageOracle(mustGetAddress("PreimageOracle")))),
// The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive.
maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1,
maxClockDuration: Duration.wrap(0) // Resolvable immediately
})
});
}
/// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
function _setFaultGameImplementation(
DisputeGameFactory _factory,
......@@ -1450,7 +1484,7 @@ contract Deploy is Deployer {
_maxGameDepth: _params.maxGameDepth,
_splitDepth: cfg.faultGameSplitDepth(),
_clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
_maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
_maxClockDuration: _params.maxClockDuration,
_vm: _params.faultVm,
_weth: _params.weth,
_anchorStateRegistry: _params.anchorStateRegistry,
......
......@@ -33,6 +33,10 @@ library GameTypes {
/// @notice A dispute game type the uses the asterisc VM
GameType internal constant ASTERISC = GameType.wrap(2);
/// @notice A dispute game type with short game duration for testing withdrawals.
/// Not intended for production use.
GameType internal constant FAST = GameType.wrap(254);
/// @notice A dispute game type that uses an alphabet vm.
/// Not intended for production use.
GameType internal constant ALPHABET = GameType.wrap(255);
......
......@@ -600,6 +600,9 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
slot = hex"d9d16d34ffb15ba3a3d852f0d403e2ce1d691fb54de27ac87cd2f993f3ec330f";
value = hex"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"1d32deecea32fd1365d10df47fc6666a05871102e61a115a5c569bca7e5de14d";
value = hex"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(anchorStateRegistryProxyAddress, slot, value);
......
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