-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #163 from valory-xyz/wormhole
feat: wormhole relayer for arbitrary msg.value-s
- Loading branch information
Showing
8 changed files
with
374 additions
and
3 deletions.
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
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 @@ | ||
{ | ||
"_format": "hh-sol-artifact-1", | ||
"contractName": "WormholeRelayer", | ||
"sourceName": "contracts/bridges/WormholeRelayer.sol", | ||
"abi": [ | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "_wormholeRelayer", | ||
"type": "address" | ||
} | ||
], | ||
"stateMutability": "nonpayable", | ||
"type": "constructor" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "uint256", | ||
"name": "provided", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "expected", | ||
"type": "uint256" | ||
} | ||
], | ||
"name": "LowerThan", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "ReentrancyGuard", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "to", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "amount", | ||
"type": "uint256" | ||
} | ||
], | ||
"name": "TransferFailed", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "ZeroAddress", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "ZeroValue", | ||
"type": "error" | ||
}, | ||
{ | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": true, | ||
"internalType": "address", | ||
"name": "sender", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "leftovers", | ||
"type": "uint256" | ||
} | ||
], | ||
"name": "LeftoversRefunded", | ||
"type": "event" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "uint16", | ||
"name": "targetChain", | ||
"type": "uint16" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "targetAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "bytes", | ||
"name": "payload", | ||
"type": "bytes" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "receiverValue", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "gasLimit", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "uint16", | ||
"name": "refundChain", | ||
"type": "uint16" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "sendPayloadToEvm", | ||
"outputs": [ | ||
{ | ||
"internalType": "uint64", | ||
"name": "sequence", | ||
"type": "uint64" | ||
} | ||
], | ||
"stateMutability": "payable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "wormholeRelayer", | ||
"outputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "", | ||
"type": "address" | ||
} | ||
], | ||
"stateMutability": "view", | ||
"type": "function" | ||
} | ||
], | ||
"bytecode": "0x60a060405260015f553480156012575f5ffd5b50604051610826380380610826833981016040819052602f91603f565b6001600160a01b0316608052606a565b5f60208284031215604e575f5ffd5b81516001600160a01b03811681146063575f5ffd5b9392505050565b60805161079761008f5f395f8181606e0152818161020301526103da01526107975ff3fe608060405260043610610028575f3560e01c80634b5ca6f41461002c578063da25b7251461005d575b5f5ffd5b61003f61003a3660046104d6565b6100b5565b60405167ffffffffffffffff90911681526020015b60405180910390f35b348015610068575f5ffd5b506100907f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610054565b5f60015f5411156100f2576040517f8beb9d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f5573ffffffffffffffffffffffffffffffffffffffff8716158061012d575073ffffffffffffffffffffffffffffffffffffffff8216155b15610164576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8816158061017457508551155b8061017d575083155b8061018a575061ffff8316155b156101c1576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc23ee3c300000000000000000000000000000000000000000000000000000000815261ffff8916600482015260248101869052604481018590525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063c23ee3c3906064016040805180830381865afa15801561025c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102809190610619565b509050348111156102cb576040517f491a2bb1000000000000000000000000000000000000000000000000000000008152346004820152602481018290526044015b60405180910390fd5b5f6102d6823461063b565b9050801561039d576040515f90329083908381818185875af1925050503d805f811461031d576040519150601f19603f3d011682016040523d82523d5f602084013e610322565b606091505b5050905080610366576040517f1c43b976000000000000000000000000000000000000000000000000000000008152326004820152602481018390526044016102c2565b60405182815232907f8e49ed3e274fbea1556bdfaa9a37a0c28445bfe26d57beaf9f04fd517aa417419060200160405180910390a2505b6040517f4b5ca6f400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b5ca6f490849061041d908e908e908e908e908e908e908e90600401610679565b60206040518083038185885af1158015610439573d5f5f3e3d5ffd5b50505050506040513d601f19601f8201168201806040525081019061045e9190610733565b60015f559a9950505050505050505050565b803561ffff81168114610481575f5ffd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610481575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f5f5f5f5f5f60e0888a0312156104ec575f5ffd5b6104f588610470565b965061050360208901610486565b9550604088013567ffffffffffffffff81111561051e575f5ffd5b8801601f81018a1361052e575f5ffd5b803567ffffffffffffffff811115610548576105486104a9565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156105b4576105b46104a9565b6040528181528282016020018c10156105cb575f5ffd5b816020840160208301375f9181016020019190915295505060608801359350608088013592506105fd60a08901610470565b915061060b60c08901610486565b905092959891949750929550565b5f5f6040838503121561062a575f5ffd5b505080516020909101519092909150565b81810381811115610673577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b61ffff8816815273ffffffffffffffffffffffffffffffffffffffff8716602082015260e060408201525f86518060e0840152806020890161010085015e5f61010082850101526101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505085606083015284608083015261ffff841660a083015261072760c083018473ffffffffffffffffffffffffffffffffffffffff169052565b98975050505050505050565b5f60208284031215610743575f5ffd5b815167ffffffffffffffff8116811461075a575f5ffd5b939250505056fea264697066735822122080362fd425a0ad8c3722a03f29d26a8c8118ef255714070a663ec545a85a33bb64736f6c634300081c0033", | ||
"deployedBytecode": "0x608060405260043610610028575f3560e01c80634b5ca6f41461002c578063da25b7251461005d575b5f5ffd5b61003f61003a3660046104d6565b6100b5565b60405167ffffffffffffffff90911681526020015b60405180910390f35b348015610068575f5ffd5b506100907f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610054565b5f60015f5411156100f2576040517f8beb9d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f5573ffffffffffffffffffffffffffffffffffffffff8716158061012d575073ffffffffffffffffffffffffffffffffffffffff8216155b15610164576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8816158061017457508551155b8061017d575083155b8061018a575061ffff8316155b156101c1576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc23ee3c300000000000000000000000000000000000000000000000000000000815261ffff8916600482015260248101869052604481018590525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063c23ee3c3906064016040805180830381865afa15801561025c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102809190610619565b509050348111156102cb576040517f491a2bb1000000000000000000000000000000000000000000000000000000008152346004820152602481018290526044015b60405180910390fd5b5f6102d6823461063b565b9050801561039d576040515f90329083908381818185875af1925050503d805f811461031d576040519150601f19603f3d011682016040523d82523d5f602084013e610322565b606091505b5050905080610366576040517f1c43b976000000000000000000000000000000000000000000000000000000008152326004820152602481018390526044016102c2565b60405182815232907f8e49ed3e274fbea1556bdfaa9a37a0c28445bfe26d57beaf9f04fd517aa417419060200160405180910390a2505b6040517f4b5ca6f400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b5ca6f490849061041d908e908e908e908e908e908e908e90600401610679565b60206040518083038185885af1158015610439573d5f5f3e3d5ffd5b50505050506040513d601f19601f8201168201806040525081019061045e9190610733565b60015f559a9950505050505050505050565b803561ffff81168114610481575f5ffd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610481575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f5f5f5f5f5f60e0888a0312156104ec575f5ffd5b6104f588610470565b965061050360208901610486565b9550604088013567ffffffffffffffff81111561051e575f5ffd5b8801601f81018a1361052e575f5ffd5b803567ffffffffffffffff811115610548576105486104a9565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156105b4576105b46104a9565b6040528181528282016020018c10156105cb575f5ffd5b816020840160208301375f9181016020019190915295505060608801359350608088013592506105fd60a08901610470565b915061060b60c08901610486565b905092959891949750929550565b5f5f6040838503121561062a575f5ffd5b505080516020909101519092909150565b81810381811115610673577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b61ffff8816815273ffffffffffffffffffffffffffffffffffffffff8716602082015260e060408201525f86518060e0840152806020890161010085015e5f61010082850101526101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505085606083015284608083015261ffff841660a083015261072760c083018473ffffffffffffffffffffffffffffffffffffffff169052565b98975050505050505050565b5f60208284031215610743575f5ffd5b815167ffffffffffffffff8116811461075a575f5ffd5b939250505056fea264697066735822122080362fd425a0ad8c3722a03f29d26a8c8118ef255714070a663ec545a85a33bb64736f6c634300081c0033", | ||
"linkReferences": {}, | ||
"deployedLinkReferences": {} | ||
} |
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,153 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.28; | ||
|
||
interface IWormhole { | ||
/// @dev Returns the price to request a relay to chain `targetChain`, using the default delivery provider | ||
/// | ||
/// @param targetChain in Wormhole Chain ID format | ||
/// @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) | ||
/// @param gasLimit gas limit with which to call `targetAddress`. | ||
/// @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay | ||
/// @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused, | ||
/// if a refundAddress is specified. | ||
/// Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a | ||
/// promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain. | ||
/// If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain. | ||
function quoteEVMDeliveryPrice( | ||
uint16 targetChain, | ||
uint256 receiverValue, | ||
uint256 gasLimit | ||
) external view returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused); | ||
|
||
/// @dev Publishes an instruction for the default delivery provider | ||
/// to relay a payload to the address `targetAddress` on chain `targetChain` | ||
/// with gas limit `gasLimit` and `msg.value` equal to `receiverValue` | ||
/// | ||
/// Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` | ||
/// `targetAddress` must implement the IWormholeReceiver interface | ||
/// | ||
/// This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)` | ||
/// | ||
/// @param targetChain in Wormhole Chain ID format | ||
/// @param targetAddress address to call on targetChain (that implements IWormholeReceiver) | ||
/// @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` | ||
/// @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) | ||
/// @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the | ||
/// `targetChainRefundPerGasUnused` rate quoted by the delivery provider | ||
/// @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format | ||
/// @param refundAddress The address on `refundChain` to deliver any refund to | ||
/// @return sequence sequence number of published VAA containing delivery instructions | ||
function sendPayloadToEvm( | ||
uint16 targetChain, | ||
address targetAddress, | ||
bytes memory payload, | ||
uint256 receiverValue, | ||
uint256 gasLimit, | ||
uint16 refundChain, | ||
address refundAddress | ||
) external payable returns (uint64 sequence); | ||
} | ||
|
||
/// @dev Provided zero address. | ||
error ZeroAddress(); | ||
|
||
/// @dev Zero value when it has to be different from zero. | ||
error ZeroValue(); | ||
|
||
/// @dev Received lower value than the expected one. | ||
/// @param provided Provided value is lower. | ||
/// @param expected Expected value. | ||
error LowerThan(uint256 provided, uint256 expected); | ||
|
||
/// @dev Failure of a native token transfer. | ||
/// @param to Address `to`. | ||
/// @param amount Token amount. | ||
error TransferFailed(address to, uint256 amount); | ||
|
||
// @dev Reentrancy guard. | ||
error ReentrancyGuard(); | ||
|
||
/// @title WormholeRelayer - Smart contract for the contract interaction with wormhole relayer with any msg.value | ||
/// @author Aleksandr Kuperman - <[email protected]> | ||
/// @author Andrey Lebedev - <[email protected]> | ||
contract WormholeRelayer { | ||
event LeftoversRefunded(address indexed sender, uint256 leftovers); | ||
|
||
// L1 Wormhole Relayer address that sends the message across the bridge | ||
address public immutable wormholeRelayer; | ||
|
||
// Reentrancy lock | ||
uint256 internal _locked = 1; | ||
|
||
/// @dev WormholeRelayer constructor. | ||
/// @param _wormholeRelayer Wormhole relayer address. | ||
constructor(address _wormholeRelayer) { | ||
wormholeRelayer = _wormholeRelayer; | ||
} | ||
|
||
/// @dev Relays a payload via Wormhole relayer to the address `targetAddress` on chain `targetChain` | ||
/// with gas limit `gasLimit` and `msg.value` equal to `receiverValue`. | ||
/// @notice This function takes arbitrary `msg.value` and adjusts the cost for relayer exact amount. | ||
/// @param targetChain in Wormhole Chain ID format. | ||
/// @param targetAddress address to call on targetChain (that implements IWormholeReceiver). | ||
/// @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`. | ||
/// @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` | ||
/// in `targetChain` currency units. | ||
/// @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the | ||
/// `targetChainRefundPerGasUnused` rate quoted by the delivery provider. | ||
/// @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format. | ||
/// @param refundAddress The address on `refundChain` to deliver any refund to. | ||
/// @return sequence Sequence number of published VAA containing delivery instructions. | ||
function sendPayloadToEvm( | ||
uint16 targetChain, | ||
address targetAddress, | ||
bytes memory payload, | ||
uint256 receiverValue, | ||
uint256 gasLimit, | ||
uint16 refundChain, | ||
address refundAddress | ||
) external payable returns (uint64 sequence) { | ||
if (_locked > 1) { | ||
revert ReentrancyGuard(); | ||
} | ||
_locked = 2; | ||
|
||
// Check for zero addresses | ||
if (targetAddress == address(0) || refundAddress == address(0)) { | ||
revert ZeroAddress(); | ||
} | ||
|
||
// Check for zero values | ||
if (targetChain == 0 || payload.length == 0 || gasLimit == 0 || refundChain == 0) { | ||
revert ZeroValue(); | ||
} | ||
|
||
// Get the message cost in order to adjust leftovers | ||
(uint256 cost, ) = IWormhole(wormholeRelayer).quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit); | ||
|
||
// Check fot msg.value to cover the cost | ||
if (cost > msg.value) { | ||
revert LowerThan(msg.value, cost); | ||
} | ||
|
||
// Return value leftovers | ||
uint256 leftovers = msg.value - cost; | ||
|
||
// Send leftover amount back to the sender, if any | ||
if (leftovers > 0) { | ||
// solhint-disable-next-line avoid-low-level-calls | ||
(bool success, ) = tx.origin.call{value: leftovers}(""); | ||
if (!success) { | ||
revert TransferFailed(tx.origin, leftovers); | ||
} | ||
|
||
emit LeftoversRefunded(tx.origin, leftovers); | ||
} | ||
|
||
// Send payload via the Wormhole relayer with exact required cost | ||
sequence = IWormhole(wormholeRelayer).sendPayloadToEvm{value: cost}(targetChain, targetAddress, payload, | ||
receiverValue, gasLimit, refundChain, refundAddress); | ||
|
||
_locked = 1; | ||
} | ||
} |
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
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
Oops, something went wrong.