Skip to content

Commit

Permalink
feat: add user specified expiration time
Browse files Browse the repository at this point in the history
  • Loading branch information
sujithsomraaj committed Sep 11, 2023
1 parent 4519ee0 commit d264191
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 61 deletions.
4 changes: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ out = "out"
libs = ["lib"]
solc = "0.8.19"

optimizer = true
optimizer = false
runs = 100
viaIR = true
viaIR = false

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
45 changes: 33 additions & 12 deletions src/MultiMessageSender.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ import "./libraries/Error.sol";
/// @title MultiMessageSender
/// @dev handles the routing of message from external sender to bridge adapters
contract MultiMessageSender {
/*///////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
IGAC public immutable gac;

uint256 public constant MINIMUM_EXPIRATION = 2 days;
uint256 public constant MAXIMUM_EXPIRATION = 30 days;

/*/////////////////////////////////////////////////////////////////
STATE VARIABLES
////////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -70,6 +76,18 @@ contract MultiMessageSender {
_;
}

/// @dev validates the expiration provided by the user
modifier validateExpiration(uint256 _expiration) {
if (_expiration < MINIMUM_EXPIRATION) {
revert Error.INVALID_EXPIRATION_MIN();
}

if (_expiration > MAXIMUM_EXPIRATION) {
revert Error.INVALID_EXPIRATION_MAX();
}
_;
}

/*/////////////////////////////////////////////////////////////////
CONSTRUCTOR
////////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -98,28 +116,33 @@ contract MultiMessageSender {
/// @param _target is the target execution point on dst chain
/// @param _callData is the data to be sent to _target by low-level call(eg. address(_target).call(_callData))
/// @param _nativeValue is the value to be sent to _target by low-level call (eg. address(_target).call{value: _nativeValue}(_callData))
function remoteCall(uint256 _dstChainId, address _target, bytes calldata _callData, uint256 _nativeValue)
external
payable
onlyCaller
{
/// @param _expiration is the validity of the calldata; before which it should be executed on the remote chain
function remoteCall(
uint256 _dstChainId,
address _target,
bytes calldata _callData,
uint256 _nativeValue,
uint256 _expiration
) external payable onlyCaller {
address[] memory excludedAdapters;
_remoteCall(_dstChainId, _target, _callData, _nativeValue, excludedAdapters);
_remoteCall(_dstChainId, _target, _callData, _nativeValue, _expiration, excludedAdapters);
}

/// @param _dstChainId is the destination chainId
/// @param _target is the target execution point on dst chain
/// @param _callData is the data to be sent to _target by low-level call(eg. address(_target).call(_callData))
/// @param _nativeValue is the value to be sent to _target by low-level call (eg. address(_target).call{value: _nativeValue}(_callData))
/// @param _excludedAdapters are the sender adapters to be excluded from relaying the message
/// @param _expiration is the validity of the calldata; before which it should be executed on the remote chain
function remoteCall(
uint256 _dstChainId,
address _target,
bytes calldata _callData,
uint256 _nativeValue,
uint256 _expiration,
address[] calldata _excludedAdapters
) external payable onlyCaller {
_remoteCall(_dstChainId, _target, _callData, _nativeValue, _excludedAdapters);
_remoteCall(_dstChainId, _target, _callData, _nativeValue, _expiration, _excludedAdapters);
}

/// @notice Add bridge sender adapters
Expand Down Expand Up @@ -183,7 +206,6 @@ contract MultiMessageSender {
struct LocalCallVars {
address[] adapters;
uint256 adapterLength;
uint256 msgExpiration;
bool[] adapterSuccess;
bytes32 msgId;
}
Expand All @@ -193,6 +215,7 @@ contract MultiMessageSender {
address _target,
bytes calldata _callData,
uint256 _nativeValue,
uint256 _expiration,
address[] memory _excludedAdapters
) private {
LocalCallVars memory v;
Expand Down Expand Up @@ -247,10 +270,8 @@ contract MultiMessageSender {
/// @dev increments nonce
++nonce;

v.msgExpiration = block.timestamp + gac.getMsgExpiryTime();

MessageLibrary.Message memory message =
MessageLibrary.Message(block.chainid, _dstChainId, _target, nonce, _callData, _nativeValue, v.msgExpiration);
MessageLibrary.Message(block.chainid, _dstChainId, _target, nonce, _callData, _nativeValue, _expiration);

v.adapterSuccess = new bool[](v.adapterLength);

Expand Down Expand Up @@ -284,7 +305,7 @@ contract MultiMessageSender {
}

emit MultiMessageMsgSent(
v.msgId, nonce, _dstChainId, _target, _callData, _nativeValue, v.msgExpiration, v.adapters, v.adapterSuccess
v.msgId, nonce, _dstChainId, _target, _callData, _nativeValue, _expiration, v.adapters, v.adapterSuccess
);
}

Expand Down
15 changes: 0 additions & 15 deletions src/controllers/GAC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ contract GAC is IGAC, Ownable {
STATE VARIABLES
//////////////////////////////////////////////////////////////*/
uint256 public dstGasLimit;
uint256 public msgExpiration;

/// @dev is the address to receive value refunds from remoteCall
address public refundAddress;
Expand Down Expand Up @@ -83,15 +82,6 @@ contract GAC is IGAC, Ownable {
emit DstGasLimitUpdated(oldLimit, _gasLimit);
}

/// @inheritdoc IGAC
function setMsgExpiryTime(uint256 _timeInSeconds) external override onlyOwner {
if (_timeInSeconds == 0) {
revert Error.ZERO_EXPIRATION_TIME();
}

msgExpiration = _timeInSeconds;
}

/// @inheritdoc IGAC
function setRefundAddress(address _refundAddress) external override onlyOwner {
if (_refundAddress == address(0)) {
Expand Down Expand Up @@ -124,11 +114,6 @@ contract GAC is IGAC, Ownable {
_gasLimit = dstGasLimit;
}

/// @inheritdoc IGAC
function getMsgExpiryTime() external view override returns (uint256 _expiration) {
_expiration = msgExpiration;
}

/// @inheritdoc IGAC
function getRefundAddress() external view override returns (address _refundAddress) {
_refundAddress = refundAddress;
Expand Down
7 changes: 0 additions & 7 deletions src/interfaces/IGAC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ interface IGAC {
/// @param _gasLimit is the limit to be set
function setGlobalMsgDeliveryGasLimit(uint256 _gasLimit) external;

/// @dev sets the message expiry time
/// @param _timeInSeconds is the expiry time for the message on dst chain
function setMsgExpiryTime(uint256 _timeInSeconds) external;

/// @dev sets the refund address for gas refunds
/// @param _refundAddress is the address to receive refunds from MMA sender
function setRefundAddress(address _refundAddress) external;
Expand Down Expand Up @@ -70,9 +66,6 @@ interface IGAC {
/// @dev returns the multi message receiver on the chain
function getMultiMessageReceiver(uint256 _chainId) external view returns (address _mmaReceiver);

/// @dev returns the expiry time of message from the time of dispatch
function getMsgExpiryTime() external view returns (uint256 _expiration);

/// @dev returns the refund address
function getRefundAddress() external view returns (address _refundAddress);
}
9 changes: 6 additions & 3 deletions src/libraries/Error.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ library Error {
/// @dev is thrown if bridge adapter already delivered the message to multi message receiver
error DUPLICATE_MESSAGE_DELIVERY_BY_ADAPTER();

/// @dev is thrown if expiration time is zero
error ZERO_EXPIRATION_TIME();

/// @dev is thrown if quorum threshold is greater than receiver adapters
error INVALID_QUORUM_THRESHOLD();

Expand All @@ -62,6 +59,12 @@ library Error {
/// @dev is thrown if caller is not admin of timelock
error CALLER_NOT_ADMIN();

/// @dev is thrown if the expiration is less than minimum expiration
error INVALID_EXPIRATION_MIN();

/// @dev is thrown if the delay is more than maximum delay
error INVALID_EXPIRATION_MAX();

/*/////////////////////////////////////////////////////////////////
ADAPTER ERRORS
////////////////////////////////////////////////////////////////*/
Expand Down
2 changes: 1 addition & 1 deletion test/Setup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ abstract contract Setup is Test {
address constant caller = address(10);
address constant owner = address(420);
address constant refundAddress = address(420420);
uint256 constant EXPIRATION_CONSTANT = 5 days;

/// @dev constants for axelar
address constant ETH_GATEWAY = 0x4F4495243837681061C4743b74B3eEdf548D56A5;
Expand Down Expand Up @@ -124,7 +125,6 @@ abstract contract Setup is Test {
vm.selectFork(fork[chainId]);

GAC gac = new GAC{salt: _salt}();
gac.setMsgExpiryTime(2 days);
gac.setMultiMessageCaller(caller);
contractAddress[chainId][bytes("GAC")] = address(gac);

Expand Down
6 changes: 5 additions & 1 deletion test/integration-tests/GracePeriodExpiry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ contract GracePeriodExpiryTest is Setup {
/// send cross-chain message using MMA infra
vm.recordLogs();
MultiMessageSender(contractAddress[1][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}(
137, address(target), abi.encode(MockUniswapReceiver.setValue.selector, ""), 0
137,
address(target),
abi.encode(MockUniswapReceiver.setValue.selector, ""),
0,
block.timestamp + EXPIRATION_CONSTANT
);

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand Down
11 changes: 7 additions & 4 deletions test/integration-tests/MessageDeadlineCheck.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ contract MessageDeadlineCheck is Setup {
137,
address(contractAddress[137][bytes("MMA_RECEIVER")]),
abi.encodeWithSelector(MultiMessageReceiver.updateReceiverAdapter.selector, adaptersToRemove, operation),
0
0,
block.timestamp + EXPIRATION_CONSTANT
);

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand Down Expand Up @@ -122,6 +123,7 @@ contract MessageDeadlineCheck is Setup {
address(contractAddress[137][bytes("MMA_RECEIVER")]),
abi.encodeWithSelector(MultiMessageReceiver.updateReceiverAdapter.selector, adaptersToRemove, operation),
0,
block.timestamp + EXPIRATION_CONSTANT,
excludeAxelar
);

Expand All @@ -148,7 +150,8 @@ contract MessageDeadlineCheck is Setup {
137,
address(contractAddress[137][bytes("MMA_RECEIVER")]),
abi.encodeWithSelector(MultiMessageReceiver.updateQuorum.selector, 1),
0
0,
block.timestamp + EXPIRATION_CONSTANT
);

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand All @@ -166,8 +169,8 @@ contract MessageDeadlineCheck is Setup {
(uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) =
_getExecParams(vm.getRecordedLogs());

/// increment the time by 2 day (delay time)
vm.warp(block.timestamp + 2 days);
/// increment the time by expiration deadline (delay time)
vm.warp(block.timestamp + EXPIRATION_CONSTANT + 1 seconds);

/// when quorum is updated here
GovernanceTimelock(contractAddress[137][bytes("TIMELOCK")]).executeTransaction(
Expand Down
6 changes: 5 additions & 1 deletion test/integration-tests/MultiMessageAggregation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ contract MultiMessageAggregationTest is Setup {
/// send cross-chain message using MMA infra
vm.recordLogs();
MultiMessageSender(contractAddress[1][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}(
137, address(target), abi.encode(MockUniswapReceiver.setValue.selector, ""), 0
137,
address(target),
abi.encode(MockUniswapReceiver.setValue.selector, ""),
0,
block.timestamp + EXPIRATION_CONSTANT
);

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand Down
3 changes: 2 additions & 1 deletion test/integration-tests/RemoteAdapterAdd.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ contract RemoteAdapterAdd is Setup {
137,
address(contractAddress[137][bytes("MMA_RECEIVER")]),
abi.encodeWithSelector(MultiMessageReceiver.updateReceiverAdapter.selector, adaptersToAdd, operation),
0
0,
block.timestamp + EXPIRATION_CONSTANT
);

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand Down
6 changes: 5 additions & 1 deletion test/integration-tests/TimelockCheck.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ contract TimelockCheckTest is Setup {
/// send cross-chain message using MMA infra
vm.recordLogs();
MultiMessageSender(contractAddress[1][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}(
137, address(target), abi.encode(MockUniswapReceiver.setValue.selector, ""), 0
137,
address(target),
abi.encode(MockUniswapReceiver.setValue.selector, ""),
0,
block.timestamp + EXPIRATION_CONSTANT
);

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand Down
Loading

0 comments on commit d264191

Please sign in to comment.