Skip to content
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

refactor(express)!: split express executable with token functionality #198

Merged
merged 4 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/empty-toes-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@axelar-network/axelar-gmp-sdk-solidity': patch
---

split express executable gateway token contracts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import { AxelarExecutable } from '../executable/AxelarExecutable.sol';
import { AxelarExecutableWithToken } from '../executable/AxelarExecutableWithToken.sol';
milapsheth marked this conversation as resolved.
Show resolved Hide resolved
import { IAxelarExecutable } from '../interfaces/IAxelarExecutable.sol';
import { IAxelarExecutableWithToken } from '../interfaces/IAxelarExecutableWithToken.sol';
import { IAxelarExpressExecutableWithToken } from '../interfaces/IAxelarExpressExecutableWithToken.sol';
import { ExpressExecutorTracker } from './ExpressExecutorTracker.sol';
import { SafeTokenTransferFrom, SafeTokenTransfer } from '../libs/SafeTransfer.sol';
import { IERC20 } from '../interfaces/IERC20.sol';

abstract contract AxelarExpressExecutable is ExpressExecutorTracker, AxelarExecutableWithToken {
abstract contract AxelarExpressExecutableWithToken is
IAxelarExpressExecutableWithToken,
ExpressExecutorTracker,
AxelarExecutableWithToken
{
using SafeTokenTransfer for IERC20;
using SafeTokenTransferFrom for IERC20;

Expand Down Expand Up @@ -141,4 +146,49 @@ abstract contract AxelarExpressExecutable is ExpressExecutorTracker, AxelarExecu

_executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount);
}

/**
* @notice Returns the express executor for a given command.
* @param commandId The commandId for the contractCall.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @return expressExecutor The address of the express executor.
*/
function getExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) external view returns (address expressExecutor) {
expressExecutor = _getExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash);
}

/**
* @notice Returns the express executor with token for a given command.
* @param commandId The commandId for the contractCallWithToken.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @param symbol The token symbol.
* @param amount The amount of tokens.
* @return expressExecutor The address of the express executor.
*/
function getExpressExecutorWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) external view returns (address expressExecutor) {
expressExecutor = _getExpressExecutorWithToken(
commandId,
sourceChain,
sourceAddress,
payloadHash,
symbol,
amount
);
}
}
137 changes: 14 additions & 123 deletions contracts/express/AxelarValuedExpressExecutable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
pragma solidity ^0.8.0;

import { AxelarExecutable } from '../executable/AxelarExecutable.sol';
import { AxelarExecutableWithToken } from '../executable/AxelarExecutableWithToken.sol';
import { IAxelarExecutable } from '../interfaces/IAxelarExecutable.sol';
import { IAxelarExecutableWithToken } from '../interfaces/IAxelarExecutableWithToken.sol';
import { IERC20 } from '../interfaces/IERC20.sol';
import { IAxelarValuedExpressExecutable } from '../interfaces/IAxelarValuedExpressExecutable.sol';
import { SafeTokenTransferFrom, SafeTokenTransfer } from '../libs/SafeTransfer.sol';
Expand All @@ -14,14 +12,14 @@ import { ExpressExecutorTracker } from './ExpressExecutorTracker.sol';

abstract contract AxelarValuedExpressExecutable is
ExpressExecutorTracker,
AxelarExecutableWithToken,
AxelarExecutable,
IAxelarValuedExpressExecutable
{
using SafeTokenTransfer for IERC20;
using SafeTokenTransferFrom for IERC20;
using SafeNativeTransfer for address payable;

constructor(address gateway_) AxelarExecutableWithToken(gateway_) {}
constructor(address gateway_) AxelarExecutable(gateway_) {}

// Returns the amount of token that this call is worth. If `tokenAddress` is `0`, then value is in terms of the native token, otherwise it's in terms of the token address.
function contractCallValue(
Expand All @@ -30,16 +28,6 @@ abstract contract AxelarValuedExpressExecutable is
bytes calldata payload
) public view virtual returns (address tokenAddress, uint256 value);

// Returns the amount of token that this call is worth. If `tokenAddress` is `0`, then value is in terms of the native token, otherwise it's in terms of the token address.
// The returned call value is in addition to the `amount` of token `symbol` being transferred with the call.
function contractCallWithTokenValue(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) public view virtual returns (address tokenAddress, uint256 value);

function execute(
bytes32 commandId,
string calldata sourceChain,
Expand Down Expand Up @@ -67,68 +55,6 @@ abstract contract AxelarValuedExpressExecutable is
}
}

function executeWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external override(AxelarExecutableWithToken, IAxelarExecutableWithToken) {
bytes32 payloadHash = keccak256(payload);
if (
!gatewayWithToken().validateContractCallAndMint(
commandId,
sourceChain,
sourceAddress,
payloadHash,
tokenSymbol,
amount
)
) revert NotApprovedByGateway();

address expressExecutor = _popExpressExecutorWithToken(
commandId,
sourceChain,
sourceAddress,
payloadHash,
tokenSymbol,
amount
);

if (expressExecutor == address(0)) {
_executeWithToken(commandId, sourceChain, sourceAddress, payload, tokenSymbol, amount);
return;
}

// slither-disable-next-line reentrancy-events
emit ExpressExecutionWithTokenFulfilled(
commandId,
sourceChain,
sourceAddress,
payloadHash,
tokenSymbol,
amount,
expressExecutor
);

{
(address tokenAddress, uint256 value) = contractCallWithTokenValue(
sourceChain,
sourceAddress,
payload,
tokenSymbol,
amount
);
_transferToExecutor(expressExecutor, tokenAddress, value);
}

{
address gatewayToken = gatewayWithToken().tokenAddresses(tokenSymbol);
IERC20(gatewayToken).safeTransfer(expressExecutor, amount);
}
}

function expressExecute(
bytes32 commandId,
string calldata sourceChain,
Expand All @@ -152,56 +78,21 @@ abstract contract AxelarValuedExpressExecutable is
_execute(commandId, sourceChain, sourceAddress, payload);
}

function expressExecuteWithToken(
/**
* @notice Returns the express executor for a given command.
* @param commandId The commandId for the contractCall.
* @param sourceChain The source chain.
* @param sourceAddress The source address.
* @param payloadHash The hash of the payload.
* @return expressExecutor The address of the express executor.
*/
function getExpressExecutor(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) external payable virtual {
if (gatewayWithToken().isCommandExecuted(commandId)) revert AlreadyExecuted();

address expressExecutor = msg.sender;
bytes32 payloadHash = keccak256(payload);

emit ExpressExecutedWithToken(
commandId,
sourceChain,
sourceAddress,
payloadHash,
symbol,
amount,
expressExecutor
);

_setExpressExecutorWithToken(
commandId,
sourceChain,
sourceAddress,
payloadHash,
symbol,
amount,
expressExecutor
);

{
(address tokenAddress, uint256 value) = contractCallWithTokenValue(
sourceChain,
sourceAddress,
payload,
symbol,
amount
);
_transferFromExecutor(expressExecutor, tokenAddress, value);
}

{
address gatewayToken = gatewayWithToken().tokenAddresses(symbol);
IERC20(gatewayToken).safeTransferFrom(expressExecutor, address(this), amount);
}

_executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount);
bytes32 payloadHash
) external view returns (address expressExecutor) {
expressExecutor = _getExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash);
}

function _transferToExecutor(
Expand Down
Loading
Loading