From 83b6824d51ceecfdc3ebef329894cd66c5f487bd Mon Sep 17 00:00:00 2001 From: Edmund Edgar Date: Tue, 12 Mar 2024 05:18:17 +0000 Subject: [PATCH] update interactions doc --- docs/interactions.md | 419 +++++++++++++++++++++++++------------------ 1 file changed, 240 insertions(+), 179 deletions(-) diff --git a/docs/interactions.md b/docs/interactions.md index 3de5342..39ad649 100644 --- a/docs/interactions.md +++ b/docs/interactions.md @@ -1,311 +1,372 @@ -# Contract interactions, L2-governed design -### Edmund Edgar, 2023-04-13 +# Contract interactions +### Edmund Edgar, 2023-04-13, last updated 2024-02-23 -This document describes the interactions between actors (users and contracts) in the single-token L2-governed version of the BORG design. +This document describes the interactions between actors (users and contracts) in Backstop. -For simplicity some contract parameters are omitted. Details of the mechanism for sending messages between L1 and L2 will depend on the L2 mechanism. +For simplicity some contract parameters are omitted. See the tests under /tests for the exact parameters. + +### Notation + * L1. or L2. denotes the layer on which the token contract is deployed + * .L1Token denotes a token native to L1. .L2Token denotes a token native to L2. + * ...X denotes one of many versions (ie there may also be a "Y" and a "Z"). + * ...-1 and ...-2 denote multiple versions that exist after a fork. + * Alice, Bob are example users, each with a unique sender address (that may exist on both L1 and L2) ## Contracts: ### Tokens -* L1.GasToken: A normal Ethereum-native token, eg DAI or WETH. -* L2.GasToken: A representation of the L1.GasToken, bridged to it. -* L2.NativeGasToken: A forkable token native to L2. There may be many of these. -* L1.GovToken, aka L1.ForkManager: A dedicated governance token that can be forked on L1. There is only one per fork. In forks this must be committed to one fork or the other. Can also replace itself while preserving balances. + * L1.L1TokenX: A normal Ethereum-native token, eg DAI or WETH. + * L2.L1TokenX: A representation of the L1.SomeToken1, bridged to layer 2. + + * L2.L2TokenX: A forkable token issued on L2. There may be many of these. + * L1.L2TokenX: A representation of the L2.L2TokenX on L1. + + * L1.GovToken, An ERC20 token representing a dedicated governance token that can be forked on L1. There is only one per fork. + * L2.GovToken, The native token version of L1.GovToken bridged to L2. ### Reality.eth instances -* L2.Reality.eth: A normal ERC20-capable reality.eth instance on L2. Uses NativeGasToken. There may be other instances supporing other tokens. -* L1.Reality.eth: A forkable ERC20-capable reality.eth instance on L1, using GovToken for bonds. + * L2.RealityETH: A normal native reality.eth instance on L2. Uses L2.GovToken. There may be other instances supporing other tokens. This role could be played by a different escalation game contract. + * L1.ForkableRealityETH_ERC20: A forkable ERC20-capable reality.eth instance on L1, using GovToken for bonds. Changing this to a different escalation game contract would require a system upgrade. + +### Arbitrators + * L2.ArbitratorX: A reality.eth arbitrator instance on L2 + * L2.AdjudicationFrameworkRequests: A adjudication framework, ie a whitelist of arbitrators such as L2.ArbitratorX. "Requests" means it uses the pull pattern. + * L2.L2ForkArbitrator: An arbitrator contract used for escalations by the adjudication framework + * L1.L1ForkArbitrator: An arbitrator contract used for escalations in governance proposals. ### L1-L2 Bridges -* L2.BridgeToL1: A contract sending messages between ledgers. -* L1.BridgeToL2: -* L2.BridgeFromL1: -* L1.BridgeFromL2: + * L1.ForkableBridge: A bridge contract like zkEVMBridge but forkable and able to handle L2.GovToken as L2 the native token. + * L2.Bridge: A bridge like a normal zkEVMBridge, but with gas token handling. Does not need to be forkable, but may be to avoid deploying multiple contracts. -ForkArbitrator +### Admin contract + * L1.ForkableRollupGovernor: A contract with the permission to upgrade the L1 system. -## Operations +### Forkable system infrastructure + * L2.L2ChainInfo: A contract on L2 that reports information about which chain it is on, what it forked over etc. + * L1.L1GlobalChainInfoPublisher: A single contract (usable by all forks) used to send information about the fork to L2.L2ChainInfo. + +### Example contracts + * L2.CrowdfunderX is an example of a crowdfunding contract you might deploy. We use this a general example of a contract that needs subjectivocratically-secure adjudication. +## Operations -### Make a crowdfund +### Make a crowdfund payable if Bob completes a task ``` - Alice L2 question_id = RealityETH.askQuestion(recipient=Bob, arbitrator=AdjudicationFramework) - Alice L2 Crowdfunder.createCrowdFund(question_id, value=1234) + Alice L2.question_id = RealityETH.askQuestion(question="Did Bob finish his job?", arbitrator=AdjudicationFrameworkRequests) + Alice L2.CrowdfunderX.createCrowdFund(question_id, value=1234) ``` ### Report an answer (uncontested) ``` - Bob L2 RealityETH.submitAnswer(question_id, 100, value=100) + Bob L2.RealityETH.submitAnswer(question_id, 100, value=100) ``` -Next step: -* Uncontested? [Claim a payout](#claim-a-payout) -* Contested? [Report an answer (contested)](#report-an-answer-contested) +#### Next step: + + * Uncontested? [Claim a payout](#claim-a-payout) + * Contested? [Report an answer (contested)](#report-an-answer-contested) ### Claim a payout ``` - Bob L2 RealityETH.claimWinnings(question_id) + Bob L2.RealityETH.claimWinnings(question_id) ``` ### Settle a crowdfund ``` - Bob L2 Crowdfunder.payOut(question_id) + Bob L2.Crowdfunder.payOut(question_id) RealityETH.resultFor(question_id) -> pays Bob ``` ### Report an answer (contested) ``` - Bob L2 RealityETH.submitAnswer(question_id, value=100) - Charlie L2 RealityETH.submitAnswer(question_id, value=200) - Bob L2 RealityETH.submitAnswer(question_id, value=400) - Charlie L2 RealityETH.submitAnswer(question_id, value=2000000) + Bob L2.RealityETH.submitAnswer(question_id, value=100) + Charlie L2.RealityETH.submitAnswer(question_id, value=200) + Bob L2.RealityETH.submitAnswer(question_id, value=400) + Charlie L2.RealityETH.submitAnswer(question_id, value=2000000) ``` ### Contest an answer ``` - Bob L2 AdjudicationFramework.requestArbitration(question_id, value=1000000) + Bob L2.AdjudicationFrameworkRequests.requestArbitration(question_id, value=1000000) ``` ### Handle an arbitration ``` - Dave L2 ArbitratorA.requestArbitration(question_id, value=500000) - AdjudicationFramework.notifyOfArbitrationRequest(question_id, Dave) + Dave L2.ArbitratorA.requestArbitration(question_id, value=500000) + AdjudicationFrameworkRequests.notifyOfArbitrationRequest(question_id, Dave) - Arby L2 ArbitratorA.submitAnswerByArbitrator(question_id, 1, Dave) - AdjudicationFramework.submitAnswerByArbitrator(question_id, 1, Bob) + Arby L2.ArbitratorA.submitAnswerByArbitrator(question_id, 1, Dave) + AdjudicationFrameworkRequests.submitAnswerByArbitrator(question_id, 1, Bob) ``` -Next step: -* Uncontested arbitration after 1 week? [Execute an arbitration](#execute-an-arbitration) -* May be contested: [Contest an arbitration](#contest-an-arbitration) +#### Next step: + + * Uncontested arbitration after 1 week? [Execute an arbitration](#execute-an-arbitration) + * May be contested: [Contest an arbitration](#contest-an-arbitration) ### Execute an arbitration ``` - Dave L2 AdjudicationFramework.executeArbitration(question_id) - NativeGasToken.transfer(Dave, 1000000) - RealityETH.submitAnswerByArbitrator(question_id, 1, Bob) + Dave L2.AdjudicationFrameworkRequests.executeArbitration(question_id) + RealityETH.submitAnswerByArbitrator(question_id, 1, Bob, value=1000000) ``` -Next step: -* Arbitration contested? [Contest an arbitration](#contest-an-arbitration) -* Arbitration uncontested? [Settle a crowdfund](#settle-a-crowdfund) +#### Next step: + + * Arbitration contested? [Contest an arbitration](#contest-an-arbitration) + * Arbitration uncontested? [Settle a crowdfund](#settle-a-crowdfund) -### Contest an arbitration. (An AdjudicationFramework could do something different here.) +### Contest an arbitration. ``` - Charlie L2 AdjudicationFramework.beginRemoveArbitrator(address arbitrator_to_remove) - contest_question_id = RealityETH.askQuestion("should we delist ArbitratorA?") - Charlie L2 RealityETH.submitAnswer(contest_question_id, 1, value=2000000) - Charlie L2 AdjudicationFramework.freezeArbitrator(contest_question_id) + Charlie L2.AdjudicationFrameworkRequests.beginRemoveArbitrator(address arbitrator_to_remove) + contest_question_id = RealityETH.askQuestion("should we delist ArbitratorA?", arbitrator=L2ForkArbitrator) + Charlie L2.RealityETH.submitAnswer(contest_question_id, 1, value=2000000) + Charlie L2.AdjudicationFrameworkRequests.freezeArbitrator(contest_question_id, ...) RealityETH.getBestAnswer(contest_question_id) RealityETH.getBond(contest_question_id) + (or if someone else added an answer provide the history and then do) + RealityETH.isHistoryOfUnfinalizedQuestionValid(contest_question_id, ...) ``` -Next step: -* Delist question finalizes as 1? [Execute an arbitrator removal](#execute-an-arbitrator-removal) -* Delist question finalizes as 0? [Cancel an arbitrator removal](#cancel-an-arbitrator-removal) -* May be contested: [Challenge an arbitration result](#challenge-an-arbitration-or-governance-result) + +NB An AdjudicationFrameworkFeed could do something different here. + +#### Next step: + + * Delist question finalizes as 1? [Execute an arbitrator removal](#execute-an-arbitrator-removal) + * Delist question finalizes as 0? [Cancel an arbitrator removal](#cancel-an-arbitrator-removal) + * May be contested: [Challenge an arbitrator addition or removal](#challenge-an-arbitrator-addition-or-removal) ### Cancel an arbitrator removal ``` - Bob L2 ForkManager.unfreezeArbitrator(contest_question_id) + Bob L2.ForkingManager.clearFailedProposition(contest_question_id) RealityETH.resultFor(contest_question_id) ``` -Next step: -* [Redeem an arbitration](#redeem-an-arbitration) +#### Next step: + * [Redeem an arbitration](#redeem-an-arbitration) ### Execute an arbitrator removal ``` - Charlie L2 AdjudicationFramework.removeArbitrator(contest_question_id) + Charlie L2.AdjudicationFrameworkRequests.executeModificationArbitratorFromAllowList(contest_question_id) RealityETH.resultFor(contest_question_id) ``` -Next step: -* [Handle an arbitration](#handle-an-arbitration) to arbitrate the question again with a different arbitrator +#### Next step: + * [Handle an arbitration](#handle-an-arbitration) to arbitrate the question again with a different arbitrator ### Propose an arbitrator addition ``` - Charlie L2 ForkArbitrator.beginAddArbitratorToAllowlist(whitelist_arbitrator, ArbitratorA) - contest_question_id = RealityETH.askQuestion("should we add ArbitratorA to AdjudicationFramework?") - Charlie L2 RealityETH.submitAnswer(contest_question_id, 1, value=2000000) + Charlie L2.AdjudicationFrameworkRequests.requestModificationOfArbitrators(0, ArbitratorA) + contest_question_id = RealityETH.askQuestion("should we add ArbitratorA to AdjudicationFrameworkRequests?") + Charlie L2.RealityETH.submitAnswer(contest_question_id, 1, value=2000000) ``` -Next step: -* [Execute an arbitrator addition](#execute-an-arbitrator-addition) if it finalizes as 1 -* Nothing to do if it finalizes as 0 -* May be escalated to [Challenge an arbitrator or governance result](#challenge-an-arbitration-or-governance-result) and create a fork +#### Next step: + * [Execute an arbitrator addition](#execute-an-arbitrator-addition) if it finalizes as 1 + * Nothing to do if it finalizes as 0 + * May be escalated to [Challenge an arbitrator addition or removal](#challenge-an-arbitrator-addition-or-removal) and create a fork ### Execute an arbitrator addition ``` - Charlie L2 RealityETH.finalizeQuestion(add_question_id) - Charlie L2 ForkArbitrator.addArbitrator(add_question_id) + Charlie L2.ForkArbitrator.executeModificationArbitratorFromAllowList(add_question_id) RealityETH.resultFor(add_question_id) ``` +### Challenge an arbitrator addition or removal +``` + Bob L2.L2ForkArbitrator.requestArbitration(contest_question_id, uint256 max_previous, ...) + # Marks this question done and freezes everything else + L2.RealityETH.notifyOfArbitrationRequest(contest_question_id, msg.sender, max_previous, value=999999); -[consumer] calls -> [reality.eth] requests arbitration from [adjudicationframework] request fulfillment from -> [arbitrator] (above) -[objector] calls -> [adjudicationframework] calls -> [reality.eth] requests arbitration from -> - [forkarbitrator] -> - - informs [reality.eth], freezing question - - informs [adjudicationframework], freezing arbitrator (also possible during escalation) - - calls L1.ForkingManager, transferring fee + # Optionally the L2ForkArbitrator waits for a delay specified by the AdjudicationFramework + [any] L2.L2ForkArbitrator.requestActivateFork(...) + AdjudicationFrameworkRequests.getInvestigationDelay() # Check the delay has passed + ChainInfo.getForkFee() # Make sure the fee is high enough + # Calculates a moneyBox address of a contract representing this contract asking about this question + BridgeFromL2.bridgeAsset(forkFee, moneyBox) +``` + +#### Next step + * [Execute a L2-created fork] or [Refund a failed L2-created fork attempt] + +### Execute a L2-created fork -### Challenge an arbitrator addition or removal ``` - Bob L2 ForkArbitrator.requestArbitration(contest_question_id, uint256 max_previous, ...) - # Marks this question done and freezes everything else - RealityETH.notifyOfArbitrationRequest(contest_question_id, msg.sender, max_previous, value=999999); + [any] L1.ForkableBridge.claimAsset(...) - # TODO: Do we need to tell the AdjudicationFramework about this? Guess not as the freezing can be handled based on reality.eth bonds + [any] L1.L1GlobalForkRequester.handlePayment(...) + L1.ForkonomicToken.transferFrom(moneyBox, this) + L1.ForkonomicToken.approve(forkManager) + L1.forkManager.initiateFork(...) + L1.ForkonomicToken.transferFrom(L1GlobalForkRequester, fee) + # Assign the Chain ID for each chain + ChainIdManager.getNextUsableChainId() + ChainIdManager.getNextUsableChainId() + # TODO: createIncentivizedMarket() - # TODO: If the contracts that can requestFork() are permissioned, this needs to be managed by some intermediate contract, or by the ForkingManager having its own list - BridgeFromL2.sendMessage(ForkingManager.requestFork(value=999999)) + [any] L1.ForkingManager.executeFork() + L1.ForkableBridge.createChildren() + L1.ForkableZkEVM.createChildren() + L1.ForkableGlobalExitRoot.createChildren() + L1.ForkonomicToken.createChildren() - [bot] L1 ForkManager.startFork(value=999999) - L2.IncentivizedMarket = createIncentivizedMarket() +``` - Bob L1 ForkManager.deployFork(false, contested question data) - # Clones ForkManager - # Clones Bridge - # Copies contested question to child RealityETH +### Refund a failed L2-created fork attempt - Charlie L1 ForkManager.deployFork(true, contested question data) - # Clones ForkManager - # Clones Bridge - # Copies contested question to child RealityETH +If another fork has been started simultaneously or the fee was too low, the fork may not be possible. In that case we unwind the request. ``` + [any] L1.ForkableBridge.claimAsset(...) -Next step: -* Wait for the fork date, then anyone can [Execute an arbitrator removal](#execute-an-arbitrator-removal) on one chain and [Cancel an arbitrator removal](#cancel-an-arbitrator-removal) on the other. + [any] L1.L1GlobalForkRequester.handlePayment(...) + L1.returnTokens(...) + L1.ForkableBridge.bridgeAsset(L2.L2ForkArbitrator) + L1.ForkableBridge.bridgeMessage(L2.L2ForkArbitrator, ...) + + [any] + L2.ForkableBridge.claimAsset() + L2.ForkableBridge.claimMessage() + L2.L2ForkArbitrator.onMessageReceived() + L2.RealityETH.cancelArbitration() + [Bob] L2.L2ForkArbitrator.claimRefund() # Transfers native token back -### Bid in the auction ``` - Bob L2 IncentivizedMarket.bid(uint256 yes_price_percent, value=tokens) - # burns own tokens - # fork.mint(msg.sender, tokens) - # Wait 1 week +#### Next step + + * Wait for the fork date, then anyone can [Execute an arbitrator removal](#execute-an-arbitrator-removal) on one chain and [Cancel an arbitrator removal](#cancel-an-arbitrator-removal) on the other. + + +### Bid in the auction + +TODO: Build this + +``` + Bob L2.IncentivizedMarket.bid(uint256 yes_price_percent, value=tokens) + burns own tokens + fork.mint(msg.sender, tokens) + + Wait 1 week IncentivizedMarket.calculateClearingPrice() - L2 .getYesNo() + L2.IncentivizedMarket.getYesNo(bob) withdraw() - # check clearing price - # decide which side the user is on by whether their price is above or below the clearing percent - # give them tokens, multiplied by inverse of clearing percent + check clearing price + decide which side the user is on by whether their price is above or below the clearing percent + give them tokens, multiplied by inverse of clearing percent - * ISSUE: Is there a simple implementation of an auction with incentivized liquidity +#### Need to build: + * Move burned funds into two pools on L1 + * Sell the burned funds in return for token A or token B on a curve + * See which has the most tokens unsold, that one is more valuable + * eg 10000 F1+F2 split into 10000 F1 and 10000 F2 + * First F1 sells for 0.01 ETH + * Second F1 sells for 0.02 ETH - Move burned funds into two pools on L1 - Sell the burned funds in return for token A or token B on a curve - See which has the most tokens unsold, that one is more valuable - eg 10000 F1+F2 split into 10000 F1 and 10000 F2 - First F1 sells for 0.01 ETH - Second F1 sells for 0.02 ETH - ``` -### Propose a routine governance change +### Propose a contract upgrade ``` - Charlie L1 ForkManager.beginUpgradeBridge - gov_question_id = RealityETH.askQuestion("should we do a routine upgrade to ForkManager XYZ?") + Charlie L1.ForkableRollupGovernor.beginProposition + upgrade_question_id = RealityETH.askQuestion("should we execute the bytecode XYZ against contract ABC?") - Charlie L1 TokenX.approve(RealityETH, 2000000) - Charlie L1 RealityETH.submitAnswer(gov_question_id, 1, 2000000) + Charlie L1.GovToken.approve(RealityETH, 2000000) + Charlie L1.RealityETH.submitAnswer(upgrade_question_id, 1, 2000000) ``` -Next step: -* Upgrade question finalizes as 1? [Execute a governance change](#execute-a-governance-change) -* Upgrade question finalizes as 0? No need to do anything -* May be contested: [Challenge an arbitration result](#challenge-an-arbitration-or-governance-result) -### Finalize a completed governance change -``` - Charlie L1 RealityETH.finalizeQuestion(gov_question_id) -``` -Next step: -* [Execute a governance change](execute-a-governance-change) +#### Next step: -NB On the normal non-forkable version of Reality.eth finalization happens automatically without a transaction. -It's its own transaction on the forkable version because forking for one question affects whether others can finalize, even within the same timestamp. + * Upgrade question finalizes as 1? [Execute a contract upgrade](#execute-a-contract-upgrade) + * Upgrade question finalizes as 0? No need to do anything + * May be contested: [Challenge a contract upgrade](#challenge-a-contract-upgrade) -### Propose an urgent governance change +### Execute a contract upgrade ``` - Charlie L1 ForkManager.beginUpgradeBridge - gov_question_id = RealityETH.askQuestion("should we freeze exits and upgrade to ForkManager XYZ?") - Charlie L1 TokenX.approve(RealityETH, 2000000) - Charlie L1 RealityETH.submitAnswer(gov_question_id, 1, 2000000) - Charlie L1 ForkManager.freezeBridges(gov_question_id) - RealityETH.getBestAnswer(gov_question_id) - RealityETH.getBond(gov_question_id) - # Update self to say there are no available bridges + Charlie L1.ForkableRollupGovernor.executeProposition(upgrade_question_id, to, bytecode) + RealityETH.resultFor(upgrade_question_id) + call(to, bytecode) + (TODO: Handle freezing of bridges etc if the proposition is urgent and there is a high bond to that effect) ``` -* Upgrade question finalizes as 1? [Execute a governance change](#execute-a-governance-change) -* Upgrade question finalizes as 0? [Clear a failed urgent governance proposal](#clear-a-failed-urgent-governance-proposal) -* May be contested: [Challenge an arbitration result](#challenge-an-arbitration-or-governance-result) -### Execute a governance change -``` - Charlie L1 ForkManager.executeBridgeUpdate(gov_question_id) - RealityETH.resultFor(gov_question_id) - # Update to reflect child forkmanager - # Has the effect of unfreezing bridges, may be new bridges +### Challenge a contract upgrade ``` + Bob L1.GovToken.approve(L1ForkArbitrator, fork_fee) + L1.L1ForkArbitrator.requestArbitration(upgrade_question_id, ...) + // Marks this question done and freezes everything else + L2.RealityETH.notifyOfArbitrationRequest(contest_question_id, msg.sender, max_previous, value=999999); + L2.ForkingManager.initiateFork() + + // TODO: This might need a getInvestigationDelay() + + [any] L1.ForkingManager.executeFork() + L1.ForkableBridge.createChildren() + L1.ForkableZkEVM.createChildren() + L1.ForkableGlobalExitRoot.createChildren() + L1.ForkonomicToken.createChildren() + L1.ForkableRealityETH_ERC20.createChildren() // TODO, may rethink -### Clear a failed urgent governance proposal + [any] L1.L1ForkArbitrator.settleChildren() ``` - Bob L1 ForkManager.clearFailedGovernanceProposal(contest_question_id) - RealityETH.resultFor(contest_question_id) - # Update self to say the previous bridge is back in action + +#### Next step + + * [Execute a contract upgrade](#execute-a-contract-upgrade) on one fork. + + +### Moving gov tokens L2->L1 ``` + Alice L2.Bridge.bridgeAsset(value=123) -### Return funds from a governance proposition or arbitrator change proposition when we fork over a different proposition + Alice L1.ForkableBridge.claimAsset() # mints erc20 value + L1.GovToken.mint(123) ``` - Bob L1 RealityETH.refund(history) - GovToken.transfer(Bob, 100) - GovToken.transfer(Charlie, 200) + +### Moving gov tokens L1->L2 ``` + Alice L1.ForkableBridge + GovToken.approve(L2.Bridge, 123) + L2.Bridge.bridgeAsset(123) [checks to make sure we're not already forked] -Next step: -* If the question is still relevant it can be begun again on either chain or both. + Alice L2.Bridge.claimAsset() +``` +### Moving L2-native ERC20 tokens L2->L1 +``` + Alice L2.L2TokenX.approve(L2.Bridge, 123) + L2.Bridge.bridgeAsset(L2TokenX, 123) -### Moving tokens to L2 + Alice L2.ForkableBridge.claimAsset() # + L1.L2TokenX.mint(Alice, 123) ``` - Alice L1 - GasToken.approve(GasTokenWrapper, 123) - GasTokenWrapper.sendToL2(123) - ForkManager.requiredBridges() - # for each bridge, usually 1 but during forks there are 2 - BridgeToL2.sendMessage("mint(Alice, 123)") - [bot] L2 BridgeFromL2.processQueue() # or similar - GasToken.mint(Alice, 123) +### Moving L2-native ERC20 tokens L1->L2 ``` + Alice L1.L2TokenX.approve(L2.Bridge, 123) + L1.ForkableBridge.bridgeAsset(L2TokenX, 123) [ checks to make sure we're not already forked ] -### Unlocking tokens on L1 + Alice L2.Bridge.claimAsset() + L2.L2TokenX.mint(Alice, 123) ``` - Bob L1 GasToken.sendToL1(123) - BridgeToL1.sendMessage("GasTokenWrapper.mint(Bob, 123")) - [bot] L1 BridgeFromL2.processQueue() or similar - GasTokenWrapper.receiveFromL2(Bob, 123) - ForkManager.requiredBridges() - # If we the transfer cannot be completed, we queue the message. - # This happens if need to hear from 2 bridges or wait for something to be updated/unfrozen - GasToken.transfer(Bob, 123) +### Moving L1-native tokens (ETH) L1->L2 ``` + Alice L1.L1TokenXWrapperWithForkChoice.approve(L1.Bridge, 123) + L1.ForkableBridge.bridgeAsset(L1TokenWrapperWithForkChoice, 123) -### Completing a move from L2 that resulted in a queued message because of a fork or governance freeze + Alice L2.Bridge.claimAsset() + L2.L1TokenX.mint(Alice, 123) - Bob L1 GasTokenWrapper.retryMessage(Bob, 123, bridge_contract) - ForkManager.requiredBridges() - GasToken.transfer(Bob, 123) +``` -### Notifying a token bridge after a fork +### Moving L1-native tokens (ETH) L2->L1 +``` + Alice L2.L1TokenWrapperWithForkChoice.approve(L1.Bridge, 123) # TODO: Make the L1TokenWrapperWithForkChoice + L2.ForkableBridge.bridgeAsset(L1TokenWrapperWithForkChoice, 123) - Alice L1 GasTokenWrapper.updateForkManager() - ForkManager.replacedByForkManager() + Alice L2.Bridge.claimAsset() TODO: Check this part + L1.L1TokenWrapperWithForkChoice.mint() +```