Skip to content

Instantly share code, notes, and snippets.

@apurbapokharel
Created August 25, 2022 06:00
Show Gist options
  • Save apurbapokharel/2d047a733341f0346560117fa342922d to your computer and use it in GitHub Desktop.
Save apurbapokharel/2d047a733341f0346560117fa342922d to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./Messages.sol";
contract Encoder is Messages {
uint8 public constant SOL_STREAM = 1;
uint8 public constant TOKEN_STREAM = 2;
uint8 public constant SOL_WITHDRAW_STREAM = 3;
uint8 public constant TOKEN_WITHDRAW_STREAM = 4;
uint8 public constant DEPOSIT_SOL = 5;
uint8 public constant DEPOSIT_TOKEN = 6;
uint8 public constant PAUSE_SOL = 7;
uint8 public constant PAUSE_TOKEN = 8;
uint8 public constant WITHDRAW_SOL = 9;
uint8 public constant WITHDRAW_TOKEN = 10;
uint8 public constant INSTANT_SOL = 11;
uint8 public constant INSTANT_TOKEN = 12;
uint8 public constant SOL_STREAM_UPDATE = 13;
uint8 public constant TOKEN_STREAM_UPDATE = 14;
uint8 public constant CANCEL_SOL = 15;
uint8 public constant CANCEL_TOKEN = 16;
function encode_native_stream(Messages.ProcessStream memory processStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
SOL_STREAM,
processStream.start_time,
processStream.end_time,
processStream.amount,
processStream.toChain,
processStream.sender,
processStream.receiver,
processStream.can_cancel,
processStream.can_update
);
}
function encode_token_stream(Messages.ProcessStreamToken memory processStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
TOKEN_STREAM,
processStream.start_time,
processStream.end_time,
processStream.amount,
processStream.toChain,
processStream.sender,
processStream.receiver,
processStream.can_cancel,
processStream.can_update,
processStream.token_mint
);
}
function encode_native_stream_update(Messages.UpdateStream memory processStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
SOL_STREAM_UPDATE,
processStream.start_time,
processStream.end_time,
processStream.amount,
processStream.toChain,
processStream.sender,
processStream.receiver
);
}
function encode_token_stream_update(Messages.UpdateStreamToken memory processStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
TOKEN_STREAM_UPDATE,
processStream.start_time,
processStream.end_time,
processStream.amount,
processStream.toChain,
processStream.sender,
processStream.receiver,
processStream.token_mint
);
}
function encode_native_withdraw_stream(Messages.ProcessWithdrawStream memory processWithdrawStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
SOL_WITHDRAW_STREAM,
processWithdrawStream.toChain,
processWithdrawStream.withdrawer
);
}
function encode_token_withdraw_stream(Messages.ProcessWithdrawStreamToken memory processWithdrawStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
TOKEN_WITHDRAW_STREAM,
processWithdrawStream.toChain,
processWithdrawStream.withdrawer,
processWithdrawStream.token_mint
);
}
function encode_process_deposit_sol(Messages.ProcessDeposit memory processDeposit) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
DEPOSIT_SOL,
processDeposit.amount,
processDeposit.toChain,
processDeposit.depositor
);
}
function encode_process_deposit_token(Messages.ProcessDepositToken memory processDeposit) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
DEPOSIT_TOKEN,
processDeposit.amount,
processDeposit.toChain,
processDeposit.depositor,
processDeposit.token_mint
);
}
function encode_process_pause_native_stream(Messages.PauseStream memory pauseStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
PAUSE_SOL,
pauseStream.toChain,
pauseStream.sender
);
}
function encode_process_pause_token_stream(Messages.PauseStreamToken memory pauseStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
PAUSE_TOKEN,
pauseStream.toChain,
pauseStream.sender,
pauseStream.token_mint
);
}
function encode_process_cancel_native_stream(Messages.CancelStream memory cancelStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
CANCEL_SOL,
cancelStream.toChain,
cancelStream.sender
);
}
function encode_process_cancel_token_stream(Messages.CancelStreamToken memory cancelStream) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
CANCEL_TOKEN,
cancelStream.toChain,
cancelStream.sender,
cancelStream.token_mint
);
}
function encode_process_native_withdrawal(Messages.ProcessWithdraw memory processWithdraw) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
WITHDRAW_SOL,
processWithdraw.amount,
processWithdraw.toChain,
processWithdraw.withdrawer
);
}
function encode_process_token_withdrawal(Messages.ProcessWithdrawToken memory processWithdraw) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
WITHDRAW_TOKEN,
processWithdraw.amount,
processWithdraw.toChain,
processWithdraw.withdrawer,
processWithdraw.token_mint
);
}
function encode_process_instant_native_transfer(Messages.ProcessTransfer memory processTransfer) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
INSTANT_SOL,
processTransfer.amount,
processTransfer.toChain,
processTransfer.sender
);
}
function encode_process_instant_token_transfer(Messages.ProcessTransferToken memory processTransfer) public pure returns (bytes memory encoded){
encoded = abi.encodePacked(
INSTANT_TOKEN,
processTransfer.amount,
processTransfer.toChain,
processTransfer.sender,
processTransfer.token_mint
);
}
}
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./Structs.sol";
interface IWormhole is Structs {
event LogMessagePublished(address indexed sender, uint64 sequence, bytes payload, uint8 consistencyLevel);
function publishMessage(
uint32 nonce,
bytes memory payload,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
function parseAndVerifyVM(bytes calldata encodedVM) external view returns (Structs.VM memory vm, bool valid, string memory reason);
function verifyVM(Structs.VM memory vm) external view returns (bool valid, string memory reason);
function verifySignatures(bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet) external pure returns (bool valid, string memory reason) ;
function parseVM(bytes memory encodedVM) external pure returns (Structs.VM memory vm);
function getGuardianSet(uint32 index) external view returns (Structs.GuardianSet memory) ;
function getCurrentGuardianSetIndex() external view returns (uint32) ;
function getGuardianSetExpiry() external view returns (uint32) ;
function governanceActionIsConsumed(bytes32 hash) external view returns (bool) ;
function isInitialized(address impl) external view returns (bool) ;
function chainId() external view returns (uint16) ;
function governanceChainId() external view returns (uint16);
function governanceContract() external view returns (bytes32);
function messageFee() external view returns (uint256) ;
}
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
interface Structs {
struct Provider {
uint16 chainId;
uint16 governanceChainId;
bytes32 governanceContract;
}
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
struct VM {
uint8 version;
uint32 timestamp;
uint32 nonce;
uint16 emitterChainId;
bytes32 emitterAddress;
uint64 sequence;
uint8 consistencyLevel;
bytes payload;
uint32 guardianSetIndex;
Signature[] signatures;
bytes32 hash;
}
struct RegisterChain {
// Governance Header
// module: "NFTBridge" left-padded
bytes32 module;
// governance action: 1
uint8 action;
// governance paket chain id: this or 0
uint16 chainId;
// Chain ID
uint16 emitterChainID;
// Emitter address. Left-zero-padded if shorter than 32 bytes
bytes32 emitterAddress;
}
}
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
/**
* @title Messages
*/
contract Messages {
struct UpdateStream {
uint64 start_time;
uint64 end_time;
uint64 amount;
uint16 toChain;
bytes sender;
bytes receiver;
}
struct UpdateStreamToken {
uint64 start_time;
uint64 end_time;
uint64 amount;
uint16 toChain;
bytes sender;
bytes receiver;
bytes token_mint;
}
struct ProcessStream {
uint64 start_time;
uint64 end_time;
uint64 amount;
uint16 toChain;
bytes sender;
bytes receiver;
uint64 can_cancel;
uint64 can_update;
}
struct ProcessStreamToken {
uint64 start_time;
uint64 end_time;
uint64 amount;
uint16 toChain;
bytes sender;
bytes receiver;
uint64 can_cancel;
uint64 can_update;
bytes token_mint;
}
struct ProcessWithdrawStream {
uint16 toChain;
bytes withdrawer;
}
struct ProcessWithdrawStreamToken {
uint16 toChain;
bytes withdrawer;
bytes token_mint;
}
struct PauseStream {
uint16 toChain;
bytes sender;
}
struct PauseStreamToken {
uint16 toChain;
bytes sender;
bytes token_mint;
}
struct CancelStream {
uint16 toChain;
bytes sender;
}
struct CancelStreamToken {
uint16 toChain;
bytes sender;
bytes token_mint;
}
struct ProcessDeposit {
uint64 amount;
uint16 toChain;
bytes depositor;
}
struct ProcessDepositToken {
uint64 amount;
uint16 toChain;
bytes depositor;
bytes token_mint;
}
struct ProcessWithdraw {
uint64 amount;
uint16 toChain;
bytes withdrawer;
}
struct ProcessTransfer {
uint64 amount;
uint16 toChain;
bytes withdrawer;
bytes sender;
}
struct ProcessTransferToken {
uint64 amount;
uint16 toChain;
bytes withdrawer;
bytes token_mint;
bytes sender;
}
struct ProcessWithdrawToken {
uint64 amount;
uint16 toChain;
bytes withdrawer;
bytes token_mint;
}
struct InstantWithdrawal {
uint64 amount;
uint16 toChain;
bytes withdrawer;
}
}
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./interfaces/IWormhole.sol";
import "./Encoder.sol";
contract Messenger is Encoder {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
uint16 public constant CHAIN_ID = 4; //3
uint8 public constant CONSISTENCY_LEVEL = 1; //15
uint32 nonce = 0;
IWormhole _wormhole;
mapping(bytes32 => bool) _completedMessages;
bytes private current_msg;
mapping(uint16 => bytes32) _applicationContracts;
event DepositSol(bytes depositor, uint64 amount, uint32 nonce);
event DepositToken(bytes depositor, bytes tokenMint, uint64 amount, uint32 nonce);
event NativeStream(bytes sender, bytes receiver, uint64 amount, uint32 nonce);
event TokenStream(bytes sender, bytes receiver, bytes tokenMint, uint64 amount, uint32 nonce);
event NativeStreamUpdate(bytes sender, bytes receiver, uint64 amount, uint32 nonce);
event TokenStreamUpdate(bytes sender, bytes receiver, bytes tokenMint, uint64 amount, uint32 nonce);
event WithdrawStream(bytes withdrawer, uint32 nonce);
event WithdrawToken(bytes withdrawer, bytes tokenMint, uint32 nonce);
event PauseNativeStream(bytes receiver, uint32 nonce);
event PauseTokenStream(bytes receiver, bytes tokenMint, uint32 nonce);
event CancelNativeStream(bytes receiver, uint32 nonce);
event CancelTokenStream(bytes receiver, bytes tokenMint, uint32 nonce);
event InstantNativeTransfer(bytes receiver, uint64 amount, uint32 nonce);
event InstantTokenTransfer(bytes receiver, bytes tokenMint, uint64 amount, uint32 nonce);
event NativeWithdrawal(bytes withdrawer, uint64 amount, uint32 nonce);
event TokenWithdrawal(bytes withdrawer, bytes tokenMint, uint64 amount, uint32 nonce);
constructor() {
// constructor(address wormholeAddress) {
_wormhole = IWormhole(0x706abc4E45D419950511e474C7B9Ed348A4a716c);
}
function wormhole() public view returns (IWormhole) {
return _wormhole;
}
function sendMsg(bytes memory str) public returns (uint64 sequence) {
sequence = wormhole().publishMessage(nonce, str, 1);
nonce = nonce + 1;
}
function process_deposit_sol(
uint64 amount,
bytes memory depositor
) public payable returns (uint64 sequence){
bytes memory sol_stream = Encoder.encode_process_deposit_sol(
Messages.ProcessDeposit({
amount: amount,
toChain: CHAIN_ID,
depositor: depositor
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit DepositSol(depositor, amount, nonce);
nonce = nonce + 1;
}
function process_deposit_token(
uint64 amount,
bytes memory depositor,
bytes memory token_mint
) public payable returns (uint64 sequence){
bytes memory token_stream = Encoder.encode_process_deposit_token(
Messages.ProcessDepositToken({
amount: amount,
toChain: CHAIN_ID,
depositor: depositor,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
token_stream,
CONSISTENCY_LEVEL
);
emit DepositToken(depositor, token_mint, amount, nonce);
nonce = nonce + 1;
}
function process_native_stream(
uint64 start_time,
uint64 end_time,
uint64 amount,
bytes memory receiver,
bytes memory sender,
uint64 can_cancel,
uint64 can_update
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_native_stream(
Messages.ProcessStream({
start_time: start_time,
end_time: end_time,
amount: amount,
toChain: CHAIN_ID,
sender: sender,
receiver: receiver,
can_cancel: can_cancel,
can_update: can_update
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit NativeStream(sender, receiver, amount, nonce);
nonce = nonce + 1;
}
function process_token_stream(
uint64 start_time,
uint64 end_time,
uint64 amount,
bytes memory receiver,
bytes memory sender,
uint64 can_cancel,
uint64 can_update,
bytes memory token_mint
) public payable returns (uint64 sequence) {
bytes memory token_stream = Encoder.encode_token_stream(
Messages.ProcessStreamToken({
start_time: start_time,
end_time: end_time,
amount: amount,
toChain: CHAIN_ID,
sender: sender,
receiver: receiver,
can_cancel: can_cancel,
can_update: can_update,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
token_stream,
CONSISTENCY_LEVEL
);
emit TokenStream(sender, receiver, token_mint, amount, nonce);
nonce = nonce + 1;
}
function process_native_stream_update(
uint64 start_time,
uint64 end_time,
uint64 amount,
bytes memory receiver,
bytes memory sender
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_native_stream_update(
Messages.UpdateStream({
start_time: start_time,
end_time: end_time,
amount: amount,
toChain: CHAIN_ID,
sender: sender,
receiver: receiver
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit NativeStreamUpdate(sender, receiver, amount, nonce);
nonce = nonce + 1;
}
function process_token_stream_update(
uint64 start_time,
uint64 end_time,
uint64 amount,
bytes memory receiver,
bytes memory sender,
bytes memory token_mint
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_token_stream_update(
Messages.UpdateStreamToken({
start_time: start_time,
end_time: end_time,
amount: amount,
toChain: CHAIN_ID,
sender: sender,
receiver: receiver,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit TokenStreamUpdate(sender, receiver, token_mint, amount, nonce);
nonce = nonce + 1;
}
// receiver will withdraw using this
function process_native_withdraw_stream(
bytes memory withdrawer
) public payable returns (uint64 sequence){
bytes memory sol_stream = Encoder.encode_native_withdraw_stream(
Messages.ProcessWithdrawStream({
toChain: CHAIN_ID,
withdrawer: withdrawer
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit WithdrawStream(withdrawer, nonce);
nonce = nonce + 1;
}
function process_token_withdraw_stream(
bytes memory withdrawer,
bytes memory token_mint
) public payable returns (uint64 sequence) {
bytes memory token_stream = Encoder.encode_token_withdraw_stream(
Messages.ProcessWithdrawStreamToken({
toChain: CHAIN_ID,
withdrawer: withdrawer,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
token_stream,
CONSISTENCY_LEVEL
);
emit WithdrawToken(withdrawer, token_mint, nonce);
nonce = nonce + 1;
}
function process_pause_native_stream(
bytes memory sender
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_process_pause_native_stream(
Messages.PauseStream({
toChain: CHAIN_ID,
sender: sender
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit PauseNativeStream(sender, nonce);
nonce = nonce + 1;
}
function process_pause_token_stream(
bytes memory sender,
bytes memory token_mint
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_process_pause_token_stream(
Messages.PauseStreamToken({
toChain: CHAIN_ID,
sender: sender,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit PauseTokenStream(sender, token_mint, nonce);
nonce = nonce + 1;
}
function process_cancel_native_stream(
bytes memory sender
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_process_cancel_native_stream(
Messages.CancelStream({
toChain: CHAIN_ID,
sender: sender
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit CancelNativeStream(sender, nonce);
nonce = nonce + 1;
}
function process_cancel_token_stream(
bytes memory sender,
bytes memory token_mint
) public payable returns (uint64 sequence) {
bytes memory sol_stream = Encoder.encode_process_cancel_token_stream(
Messages.CancelStreamToken({
toChain: CHAIN_ID,
sender: sender,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit CancelTokenStream(sender, token_mint, nonce);
nonce = nonce + 1;
}
// sender will transfer to receiver
function process_instant_native_transfer(
uint64 amount,
bytes memory sender,
bytes memory withdrawer
) public payable returns (uint64 sequence){
bytes memory sol_stream = Encoder.encode_process_instant_native_transfer(
Messages.ProcessTransfer({
amount: amount,
toChain: CHAIN_ID,
withdrawer: withdrawer,
sender: sender
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit InstantNativeTransfer(sender, amount, nonce);
nonce = nonce + 1;
}
// sender will transfer to receiver
function process_instant_token_transfer(
uint64 amount,
bytes memory sender,
bytes memory withdrawer,
bytes memory token_mint
) public payable returns (uint64 sequence){
bytes memory token_stream = Encoder.encode_process_instant_token_transfer(
Messages.ProcessTransferToken({
amount: amount,
toChain: CHAIN_ID,
withdrawer: withdrawer,
token_mint: token_mint,
sender: sender
})
);
sequence = wormhole().publishMessage(
nonce,
token_stream,
CONSISTENCY_LEVEL
);
emit InstantTokenTransfer(sender, token_mint, amount, nonce);
nonce = nonce + 1;
}
// sender will withdraw
function process_native_withdrawal(
uint64 amount,
bytes memory sender
) public payable returns (uint64 sequence){
bytes memory sol_stream = Encoder.encode_process_native_withdrawal(
Messages.ProcessWithdraw({
amount: amount,
toChain: CHAIN_ID,
withdrawer: sender
})
);
sequence = wormhole().publishMessage(
nonce,
sol_stream,
CONSISTENCY_LEVEL
);
emit NativeWithdrawal(sender, amount, nonce);
nonce = nonce + 1;
}
// sender will withdraw
function process_token_withdrawal(
uint64 amount,
bytes memory sender,
bytes memory token_mint
) public payable returns (uint64 sequence){
bytes memory token_stream = Encoder.encode_process_token_withdrawal(
Messages.ProcessWithdrawToken({
amount: amount,
toChain: CHAIN_ID,
withdrawer: sender,
token_mint: token_mint
})
);
sequence = wormhole().publishMessage(
nonce,
token_stream,
CONSISTENCY_LEVEL
);
emit TokenWithdrawal(sender, token_mint, amount, nonce);
nonce = nonce + 1;
}
/**
Registers it's sibling applications on other chains as the only ones that can send this instance messages
*/
function registerApplicationContracts(
uint16 chainId,
bytes32 applicationAddr
) public {
// require(msg.sender == owner, "Only owner can register new chains!");
_applicationContracts[chainId] = applicationAddr;
}
function receiveEncodedMsg(bytes memory encodedMsg) public {
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole()
.parseAndVerifyVM(encodedMsg);
//1. Check Wormhole Guardian Signatures
// If the VM is NOT valid, will return the reason it's not valid
// If the VM IS valid, reason will be blank
require(valid, reason);
//2. Check if the Emitter Chain contract is registered
require(
_applicationContracts[vm.emitterChainId] == vm.emitterAddress,
"Invalid Emitter Address!"
);
//3. Check that the message hasn't already been processed
require(!_completedMessages[vm.hash], "Message already processed");
_completedMessages[vm.hash] = true;
//Do the thing
current_msg = vm.payload;
}
function getCurrentMsg() public view returns (bytes memory) {
return current_msg;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment