forked from paradigmxyz/reth
-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(gwyneth): incorporate booster sample contracts #26
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fa9f982
Integrate and make contracts compiling
853e2cd
move sync-only consuem and write to XChain
784f613
add xtransfer and token example
aed907b
meeting outcomes
4f649b3
Merge pull request #28 from taikoxyz/modify_erc20_xchain_version_inhe…
adaki2004 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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,8 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import "../gwyneth/XChainERC20Token.sol"; | ||
|
||
contract xERC20Example is XChainERC20Token { | ||
constructor(string memory name_, string memory symbol_, address premintAddress_, uint256 premintAmount_ ) XChainERC20Token(name_, symbol_, premintAddress_, premintAmount_ ) {} | ||
} |
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,44 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity >=0.8.12 <0.9.0; | ||
|
||
import "./XChain.sol"; | ||
|
||
contract Bus is XChain { | ||
// Stored only on the target chain | ||
mapping (bytes32 => bool) public consumed; | ||
|
||
function isMessageSent(bytes32 messageHash, uint busID) external view returns (bool) { | ||
return messages[busID] == messageHash; | ||
} | ||
|
||
function write(bytes memory message) public override returns (uint) { | ||
messages.push(calcMessageHash(message)); | ||
return messages.length - 1; | ||
} | ||
|
||
function consume(uint fromChainId, bytes memory message, bytes calldata proof) public override { | ||
ProofType proofType = ProofType(uint16(bytes2(proof[:2]))); | ||
if (proofType == ProofType.ASYNC) { | ||
// Decode the proof | ||
AsyncBusProof memory busProof = abi.decode(proof[2:], (AsyncBusProof)); | ||
|
||
// Calculate the message hash | ||
bytes32 messageHash = calcMessageHash(message); | ||
|
||
// Do the call on the source chain to see if the message was sent there | ||
xCallOptions(fromChainId, true, busProof.boosterCallProof); | ||
bool isSent = this.isMessageSent(messageHash, busProof.busID); | ||
require(isSent == true); | ||
|
||
// Make sure this is the first and last time this message is consumed | ||
require(consumed[messageHash] == false); | ||
consumed[messageHash] = true; | ||
} else if (proofType == ProofType.SYNC) { | ||
// Sync system with shared validity (e.g.: like a SignalService shared validity thing) | ||
write(message); | ||
} else { | ||
revert("INVALID BUS PROOF"); | ||
} | ||
} | ||
} |
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,68 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity >=0.8.12 <0.9.0; | ||
|
||
// EVM library | ||
library EVM { | ||
// precompile addresses | ||
address constant xCallOptionsAddress = address(0x1100); | ||
|
||
uint constant l1ChainId = 1; | ||
uint constant version = 1; | ||
|
||
function xCallOnL1() | ||
public | ||
view | ||
{ | ||
xCallOptions(l1ChainId); | ||
} | ||
|
||
function xCallOptions(uint chainID) | ||
public | ||
view | ||
{ | ||
xCallOptions(chainID, true); | ||
} | ||
|
||
function xCallOptions(uint chainID, bool sandbox) | ||
public | ||
view | ||
{ | ||
xCallOptions(chainID, sandbox, address(0), address(0)); | ||
} | ||
|
||
function xCallOptions(uint chainID, bool sandbox, address txOrigin, address msgSender) | ||
public | ||
view | ||
{ | ||
xCallOptions(chainID, sandbox, txOrigin, msgSender, 0x0, ""); | ||
} | ||
|
||
function xCallOptions(uint chainID, bool sandbox, bytes32 blockHash, bytes memory proof) | ||
public | ||
view | ||
{ | ||
xCallOptions(chainID, sandbox, address(0), address(0), blockHash, proof); | ||
} | ||
|
||
function xCallOptions(uint chainID, bool sandbox, address txOrigin, address msgSender, bytes32 blockHash, bytes memory proof) | ||
public | ||
view | ||
{ | ||
// This precompile is not supported on L1 | ||
require(chainID != l1ChainId); | ||
|
||
// Call the custom precompile | ||
bytes memory input = abi.encodePacked(version, chainID, sandbox, txOrigin, msgSender, blockHash, proof); | ||
(bool success, ) = xCallOptionsAddress.staticcall(input); | ||
require(success); | ||
} | ||
|
||
function isOnL1() public view returns (bool) { | ||
return chainId() == l1ChainId; | ||
} | ||
|
||
function chainId() public view returns (uint256) { | ||
return block.chainid; | ||
} | ||
} |
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,150 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity >=0.8.12 <0.9.0; | ||
|
||
import "./EVM.sol"; | ||
|
||
contract XChain { | ||
struct XChainCallProof { | ||
uint chainID; | ||
uint blockID; | ||
bytes callProof; | ||
} | ||
|
||
struct AsyncBusProof { | ||
uint busID; | ||
bytes boosterCallProof; | ||
} | ||
|
||
struct AsyncBusProofV2 { | ||
uint blockNumber; | ||
uint busID; | ||
} | ||
|
||
enum ProofType { | ||
INVALID, | ||
ASYNC, | ||
SYNC | ||
} | ||
|
||
// Messages are stored only on the source chain for ASYNC messages. | ||
// In SYNC mode, the message is stored on both the source and the target chain. | ||
bytes32[] public messages; | ||
|
||
// Only stored on L1 | ||
// Currently getBlockHash() is not supported via the new Taiko Gwyneth | ||
//ITaiko public taiko; | ||
// todo (@Brecht): XChain has a bus property but Bus is an XChain (inherits). It does not make too much sense to me, or maybe i'm missing the point ? | ||
//Bus public bus; | ||
|
||
// Event that is logged when a transaction on a chain also needs to be executed on another chain | ||
event ExecuteNextOn(uint chainID, address from, address target, bytes callData); | ||
|
||
error FUNC_NOT_IMPLEMENTED(); | ||
error NO_NEED_BUS_PROOF_ALL_ASYNC(); | ||
|
||
function init(/*ITaiko _taiko*/) | ||
internal | ||
{ | ||
//taiko = _taiko; | ||
} | ||
|
||
modifier notImplemented() { | ||
revert FUNC_NOT_IMPLEMENTED(); | ||
_; | ||
} | ||
|
||
// xExecuteOn functions need | ||
// - to be external | ||
modifier xExecuteOn(uint chainID) { | ||
if (EVM.chainId() == chainID) { | ||
_; | ||
} else { | ||
EVM.xCallOptions(chainID, true); | ||
(bool success, bytes memory data) = address(this).staticcall(msg.data); | ||
require(success); | ||
// Just pass through the return data | ||
assembly { | ||
return(add(data, 32), mload(data)) | ||
} | ||
} | ||
} | ||
|
||
// xFunctions functions need | ||
// - to be external | ||
// - to have `bytes proof` as the last function argument | ||
modifier xFunction(uint fromChainId, uint toChainId, bytes calldata proof) { | ||
// Current code is written with async case ! (This is outdated there, no need to run if running in sync. comp mode) | ||
if (fromChainId != toChainId) { | ||
// Remove the proof data from the message data | ||
// Bytes arays are padded to 32 bytes and start with a 32 byte length value | ||
uint messageLength = msg.data.length - ((proof.length + 31) / 32 + 1) * 32; | ||
bytes memory message = msg.data; | ||
assembly { | ||
mstore(message, messageLength) | ||
} | ||
|
||
// Use the bus to communicate between chains | ||
if (EVM.chainId() == fromChainId) { | ||
uint busID = write(message); | ||
|
||
// Always suggest doing an async proof for now on the target chain | ||
AsyncBusProofV2 memory asyncProof = AsyncBusProofV2({ | ||
busID: busID, | ||
blockNumber: block.number | ||
}); | ||
bytes memory encodedProof = abi.encode(asyncProof); | ||
bytes memory callData = bytes(string.concat(string(new bytes(0x0001)), string(message), string(encodedProof))); | ||
emit ExecuteNextOn(toChainId, address(0), address(this), callData); | ||
} else if (EVM.chainId() == toChainId) { | ||
consume(fromChainId, message, proof); | ||
} else { | ||
revert(); | ||
} | ||
} | ||
_; | ||
} | ||
|
||
// These could also be exposed using a precompile because we could get them from public input, | ||
// but that requires extra work so let's just fetch them from L1 for now | ||
function getBlockHash(uint chainID, uint blockID) external view xExecuteOn(EVM.l1ChainId) returns (bytes32) { | ||
// todo(@Brecht): Currently not supported or well, at least TaikoL1 does not have it with the current design. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, outdated! Hmmmm only needed for async case so let's skip for now. |
||
//return taiko.getBlockHash(chainID, blockID); | ||
} | ||
|
||
function calcMessageHash(bytes memory message) internal view returns (bytes32) { | ||
return keccak256(abi.encode(EVM.chainId(), msg.sender, message)); | ||
} | ||
|
||
// Supports setting the call options using any L2 in the booster network. | ||
// This is done by first checking the validity of the blockhash of the specified L2. | ||
function xCallOptions(uint chainID, bool sandbox, bytes memory proof) internal view { | ||
// Decode the proof | ||
XChainCallProof memory chainCallProof = abi.decode(proof, (XChainCallProof)); | ||
require(chainID == chainCallProof.chainID); | ||
|
||
// If the source chain isn't L1, go fetch the block header of the L2 stored on L1 | ||
bytes32 blockHash = 0x0; | ||
if (chainID != EVM.l1ChainId) { | ||
|
||
blockHash = this.getBlockHash(chainID, chainCallProof.blockID); | ||
} | ||
|
||
// Do the call on the specified chain | ||
EVM.xCallOptions(chainID, sandbox, blockHash, chainCallProof.callProof); | ||
} | ||
|
||
// todo (@Brecht): | ||
// There was a circular reference (XBus inherits from XChain, while also XChain has a XBus property, so i made these to compile) | ||
// They will be inherited in XBus, but basically XBus can be incorporated into XChain, no ? | ||
|
||
// Question (Brecht): | ||
//- Shall we put back these functionalities to bus ? | ||
//- Shall we remove (as i did here) the ownership of the bus - then use the previous implementation ? (notImplemented modifier) and overwrite in the child "bus" ? | ||
|
||
// Currently, supposingly there is "synchronous composability", so let's assume a synchronous world | ||
function write(bytes memory message) public virtual notImplemented returns (uint) {} | ||
|
||
// Even tho the function just passes thru to write(), it is needed to bus-compatibility, where the consume function will differ | ||
function consume(uint256 /*fromChainId*/, bytes memory message, bytes calldata proof) public notImplemented virtual {} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bus might still be needed for async transactions to pass data from one chain to the other, but I guess to keep things simple let's assume synchronous everywhere for now.