Latest 25 from a total of 944,033 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Execute With Tok... | 82075877 | 3 mins ago | IN | 0 POL | 0.08463458 | ||||
| Express Execute ... | 82075849 | 4 mins ago | IN | 0 POL | 0.43291153 | ||||
| Express Execute ... | 82075569 | 13 mins ago | IN | 0 POL | 0.21337378 | ||||
| Fund And Run Mul... | 82075335 | 21 mins ago | IN | 0 POL | 0.1589897 | ||||
| Execute With Tok... | 82075313 | 22 mins ago | IN | 0 POL | 0.08168866 | ||||
| Express Execute ... | 82075286 | 22 mins ago | IN | 0 POL | 0.11074109 | ||||
| Express Execute ... | 82075281 | 23 mins ago | IN | 0 POL | 0.22947501 | ||||
| Execute With Tok... | 82075274 | 23 mins ago | IN | 0 POL | 0.07806952 | ||||
| Express Execute ... | 82075235 | 24 mins ago | IN | 0 POL | 0.23800356 | ||||
| Execute With Tok... | 82075222 | 25 mins ago | IN | 0 POL | 0.06654451 | ||||
| Express Execute ... | 82074545 | 47 mins ago | IN | 0 POL | 0.15340795 | ||||
| Execute With Tok... | 82074477 | 49 mins ago | IN | 0 POL | 0.04533961 | ||||
| Execute With Tok... | 82074275 | 56 mins ago | IN | 0 POL | 0.05450998 | ||||
| Execute With Tok... | 82074256 | 57 mins ago | IN | 0 POL | 0.05359897 | ||||
| Execute With Tok... | 82074071 | 1 hr ago | IN | 0 POL | 0.07305226 | ||||
| Express Execute ... | 82073957 | 1 hr ago | IN | 0 POL | 0.26862815 | ||||
| Execute With Tok... | 82073749 | 1 hr ago | IN | 0 POL | 0.08064606 | ||||
| Express Execute ... | 82073724 | 1 hr ago | IN | 0 POL | 0.31154839 | ||||
| Express Execute ... | 82073641 | 1 hr ago | IN | 0 POL | 0.30837508 | ||||
| Execute With Tok... | 82073497 | 1 hr ago | IN | 0 POL | 0.05881788 | ||||
| Express Execute ... | 82073391 | 1 hr ago | IN | 0 POL | 0.17368129 | ||||
| Express Execute ... | 82073339 | 1 hr ago | IN | 0 POL | 0.17146504 | ||||
| Execute With Tok... | 82073257 | 1 hr ago | IN | 0 POL | 0.05455517 | ||||
| Execute With Tok... | 82073100 | 1 hr ago | IN | 0 POL | 0.06142104 | ||||
| Express Execute ... | 82073072 | 1 hr ago | IN | 0 POL | 0.19387 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 82075454 | 17 mins ago | 0.56381548 POL | ||||
| 82075454 | 17 mins ago | 0.56381548 POL | ||||
| 82074439 | 51 mins ago | 6.26687329 POL | ||||
| 82074439 | 51 mins ago | 6.26687329 POL | ||||
| 82074103 | 1 hr ago | 1.79325046 POL | ||||
| 82074103 | 1 hr ago | 1.79325046 POL | ||||
| 82074007 | 1 hr ago | 5.18019473 POL | ||||
| 82074007 | 1 hr ago | 5.18019473 POL | ||||
| 82073707 | 1 hr ago | 4.20877632 POL | ||||
| 82073707 | 1 hr ago | 4.20877632 POL | ||||
| 82073272 | 1 hr ago | 0.56261799 POL | ||||
| 82073272 | 1 hr ago | 0.56261799 POL | ||||
| 82072679 | 1 hr ago | 0.56214837 POL | ||||
| 82072679 | 1 hr ago | 0.56214837 POL | ||||
| 82072163 | 2 hrs ago | 0.77203662 POL | ||||
| 82072163 | 2 hrs ago | 0.77203662 POL | ||||
| 82071588 | 2 hrs ago | 2.15380014 POL | ||||
| 82071588 | 2 hrs ago | 2.15380014 POL | ||||
| 82071490 | 2 hrs ago | 0.25904732 POL | ||||
| 82071490 | 2 hrs ago | 46.1 POL | ||||
| 82071326 | 2 hrs ago | 1.0140825 POL | ||||
| 82071326 | 2 hrs ago | 1.0140825 POL | ||||
| 82070596 | 2 hrs ago | 0.56200577 POL | ||||
| 82068898 | 3 hrs ago | 0.6623509 POL | ||||
| 82068898 | 3 hrs ago | 0.6623509 POL |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SquidRouterProxy
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 99999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {Proxy} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradables/Proxy.sol";
contract SquidRouterProxy is Proxy {
function contractId() internal pure override returns (bytes32 id) {
id = keccak256("squid-router");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import './IUpgradable.sol';
// This should be owned by the microservice that is paying for gas.
interface IAxelarGasService is IUpgradable {
error NothingReceived();
error TransferFailed();
error InvalidAddress();
event GasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasAdded(bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress);
event NativeGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress);
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
function addGas(
bytes32 txHash,
uint256 txIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
function addNativeGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
function collectFees(address payable receiver, address[] calldata tokens) external;
function refund(
address payable receiver,
address token,
uint256 amount
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
// General interface for upgradable contracts
interface IUpgradable {
error NotOwner();
error InvalidOwner();
error InvalidCodeHash();
error InvalidImplementation();
error SetupFailed();
error NotProxy();
event Upgraded(address indexed newImplementation);
event OwnershipTransferred(address indexed newOwner);
// Get current owner
function owner() external view returns (address);
function contractId() external pure returns (bytes32);
function implementation() external view returns (address);
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external;
function setup(bytes calldata data) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarGateway } from '../interfaces/IAxelarGateway.sol';
import { IERC20 } from '../interfaces/IERC20.sol';
import { IAxelarForecallable } from '../interfaces/IAxelarForecallable.sol';
contract AxelarForecallable is IAxelarForecallable {
IAxelarGateway public immutable gateway;
//keccak256('forecallers');
uint256 public constant FORECALLERS_SALT = 0xdb79ee324babd8834c3c1a1a2739c004fce73b812ac9f637241ff47b19e4b71f;
constructor(address gateway_) {
if (gateway_ == address(0)) revert InvalidAddress();
gateway = IAxelarGateway(gateway_);
}
function getForecaller(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) public view override returns (address forecaller) {
bytes32 pos = keccak256(abi.encode(sourceChain, sourceAddress, payload, FORECALLERS_SALT));
// solhint-disable-next-line no-inline-assembly
assembly {
forecaller := sload(pos)
}
}
function _setForecaller(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
address forecaller
) internal {
bytes32 pos = keccak256(abi.encode(sourceChain, sourceAddress, payload, FORECALLERS_SALT));
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(pos, forecaller)
}
}
function forecall(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external {
_checkForecall(sourceChain, sourceAddress, payload, msg.sender);
if (getForecaller(sourceChain, sourceAddress, payload) != address(0)) revert AlreadyForecalled();
_setForecaller(sourceChain, sourceAddress, payload, msg.sender);
_execute(sourceChain, sourceAddress, payload);
}
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external override {
bytes32 payloadHash = keccak256(payload);
if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, payloadHash))
revert NotApprovedByGateway();
address forecaller = getForecaller(sourceChain, sourceAddress, payload);
if (forecaller != address(0)) {
_setForecaller(sourceChain, sourceAddress, payload, address(0));
} else {
_execute(sourceChain, sourceAddress, payload);
}
}
function getForecallerWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) public view override returns (address forecaller) {
bytes32 pos = keccak256(abi.encode(sourceChain, sourceAddress, payload, symbol, amount, FORECALLERS_SALT));
// solhint-disable-next-line no-inline-assembly
assembly {
forecaller := sload(pos)
}
}
function _setForecallerWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address forecaller
) internal {
bytes32 pos = keccak256(abi.encode(sourceChain, sourceAddress, payload, symbol, amount, FORECALLERS_SALT));
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(pos, forecaller)
}
}
function forecallWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external override {
address token = gateway.tokenAddresses(tokenSymbol);
uint256 amountPost = amountPostFee(amount, payload);
_safeTransferFrom(token, msg.sender, amountPost);
_checkForecallWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount, msg.sender);
if (getForecallerWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount) != address(0))
revert AlreadyForecalled();
_setForecallerWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount, msg.sender);
_executeWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amountPost);
}
function executeWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external override {
bytes32 payloadHash = keccak256(payload);
if (
!gateway.validateContractCallAndMint(
commandId,
sourceChain,
sourceAddress,
payloadHash,
tokenSymbol,
amount
)
) revert NotApprovedByGateway();
address forecaller = getForecallerWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount);
if (forecaller != address(0)) {
_setForecallerWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount, address(0));
address token = gateway.tokenAddresses(tokenSymbol);
_safeTransfer(token, forecaller, amount);
} else {
_executeWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount);
}
}
function _execute(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) internal virtual {}
function _executeWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) internal virtual {}
// Override this to keep a fee.
function amountPostFee(
uint256 amount,
bytes calldata /*payload*/
) public virtual override returns (uint256) {
return amount;
}
// Override this and revert if you want to only allow certain people/calls to be able to forecall.
function _checkForecall(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
address forecaller
) internal virtual {}
// Override this and revert if you want to only allow certain people/calls to be able to forecall.
function _checkForecallWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount,
address forecaller
) internal virtual {}
function _safeTransfer(
address tokenAddress,
address receiver,
uint256 amount
) internal {
(bool success, bytes memory returnData) = tokenAddress.call(
abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || tokenAddress.code.length == 0) revert TransferFailed();
}
function _safeTransferFrom(
address tokenAddress,
address from,
uint256 amount
) internal {
(bool success, bytes memory returnData) = tokenAddress.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, address(this), amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || tokenAddress.code.length == 0) revert TransferFailed();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarGateway } from '../interfaces/IAxelarGateway.sol';
interface IAxelarExecutable {
error InvalidAddress();
error NotApprovedByGateway();
function gateway() external view returns (IAxelarGateway);
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external;
function executeWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarExecutable } from '../interfaces/IAxelarExecutable.sol';
interface IAxelarForecallable is IAxelarExecutable {
error AlreadyForecalled();
error TransferFailed();
function forecall(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external;
function forecallWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external;
function getForecaller(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external returns (address forecaller);
function getForecallerWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) external returns (address forecaller);
function amountPostFee(uint256 amount, bytes calldata payload) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAxelarGateway {
/**********\
|* Errors *|
\**********/
error NotSelf();
error NotProxy();
error InvalidCodeHash();
error SetupFailed();
error InvalidAuthModule();
error InvalidTokenDeployer();
error InvalidAmount();
error InvalidChainId();
error InvalidCommands();
error TokenDoesNotExist(string symbol);
error TokenAlreadyExists(string symbol);
error TokenDeployFailed(string symbol);
error TokenContractDoesNotExist(address token);
error BurnFailed(string symbol);
error MintFailed(string symbol);
error InvalidSetMintLimitsParams();
error ExceedMintLimit(string symbol);
/**********\
|* Events *|
\**********/
event TokenSent(
address indexed sender,
string destinationChain,
string destinationAddress,
string symbol,
uint256 amount
);
event ContractCall(
address indexed sender,
string destinationChain,
string destinationContractAddress,
bytes32 indexed payloadHash,
bytes payload
);
event ContractCallWithToken(
address indexed sender,
string destinationChain,
string destinationContractAddress,
bytes32 indexed payloadHash,
bytes payload,
string symbol,
uint256 amount
);
event Executed(bytes32 indexed commandId);
event TokenDeployed(string symbol, address tokenAddresses);
event ContractCallApproved(
bytes32 indexed commandId,
string sourceChain,
string sourceAddress,
address indexed contractAddress,
bytes32 indexed payloadHash,
bytes32 sourceTxHash,
uint256 sourceEventIndex
);
event ContractCallApprovedWithMint(
bytes32 indexed commandId,
string sourceChain,
string sourceAddress,
address indexed contractAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
bytes32 sourceTxHash,
uint256 sourceEventIndex
);
event TokenMintLimitUpdated(string symbol, uint256 limit);
event OperatorshipTransferred(bytes newOperatorsData);
event Upgraded(address indexed implementation);
/********************\
|* Public Functions *|
\********************/
function sendToken(
string calldata destinationChain,
string calldata destinationAddress,
string calldata symbol,
uint256 amount
) external;
function callContract(
string calldata destinationChain,
string calldata contractAddress,
bytes calldata payload
) external;
function callContractWithToken(
string calldata destinationChain,
string calldata contractAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) external;
function isContractCallApproved(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
address contractAddress,
bytes32 payloadHash
) external view returns (bool);
function isContractCallAndMintApproved(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
address contractAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) external view returns (bool);
function validateContractCall(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) external returns (bool);
function validateContractCallAndMint(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) external returns (bool);
/***********\
|* Getters *|
\***********/
function authModule() external view returns (address);
function tokenDeployer() external view returns (address);
function tokenMintLimit(string memory symbol) external view returns (uint256);
function tokenMintAmount(string memory symbol) external view returns (uint256);
function allTokensFrozen() external view returns (bool);
function implementation() external view returns (address);
function tokenAddresses(string memory symbol) external view returns (address);
function tokenFrozen(string memory symbol) external view returns (bool);
function isCommandExecuted(bytes32 commandId) external view returns (bool);
function adminEpoch() external view returns (uint256);
function adminThreshold(uint256 epoch) external view returns (uint256);
function admins(uint256 epoch) external view returns (address[] memory);
/*******************\
|* Admin Functions *|
\*******************/
function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external;
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata setupParams
) external;
/**********************\
|* External Functions *|
\**********************/
function setup(bytes calldata params) external;
function execute(bytes calldata input) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
error InvalidAccount();
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// General interface for upgradable contracts
interface IUpgradable {
error NotOwner();
error InvalidOwner();
error InvalidCodeHash();
error InvalidImplementation();
error SetupFailed();
error NotProxy();
event Upgraded(address indexed newImplementation);
event OwnershipTransferred(address indexed newOwner);
// Get current owner
function owner() external view returns (address);
function contractId() external pure returns (bytes32);
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external;
function setup(bytes calldata data) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library StringToAddress {
function toAddress(string memory _a) internal pure returns (address) {
bytes memory tmp = bytes(_a);
if (tmp.length != 42) return address(0);
uint160 iaddr = 0;
uint8 b;
for (uint256 i = 2; i < 42; i++) {
b = uint8(tmp[i]);
if ((b >= 97) && (b <= 102)) b -= 87;
else if ((b >= 65) && (b <= 70)) b -= 55;
else if ((b >= 48) && (b <= 57)) b -= 48;
else return address(0);
iaddr |= uint160(uint256(b) << ((41 - i) << 2));
}
return address(iaddr);
}
}
library AddressToString {
function toString(address a) internal pure returns (string memory) {
bytes memory data = abi.encodePacked(a);
bytes memory characters = '0123456789abcdef';
bytes memory byteString = new bytes(2 + data.length * 2);
byteString[0] = '0';
byteString[1] = 'x';
for (uint256 i; i < data.length; ++i) {
byteString[2 + i * 2] = characters[uint256(uint8(data[i] >> 4))];
byteString[3 + i * 2] = characters[uint256(uint8(data[i] & 0x0f))];
}
return string(byteString);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IUpgradable } from '../interfaces/IUpgradable.sol';
contract Proxy {
error InvalidImplementation();
error SetupFailed();
error EtherNotAccepted();
error NotOwner();
error AlreadyInitialized();
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
// keccak256('owner')
bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
constructor() {
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(_OWNER_SLOT, caller())
}
}
function init(
address implementationAddress,
address newOwner,
bytes memory params
) external {
address owner;
// solhint-disable-next-line no-inline-assembly
assembly {
owner := sload(_OWNER_SLOT)
}
if (msg.sender != owner) revert NotOwner();
if (implementation() != address(0)) revert AlreadyInitialized();
if (IUpgradable(implementationAddress).contractId() != contractId()) revert InvalidImplementation();
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(_IMPLEMENTATION_SLOT, implementationAddress)
sstore(_OWNER_SLOT, newOwner)
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = implementationAddress.delegatecall(
//0x9ded06df is the setup selector.
abi.encodeWithSelector(0x9ded06df, params)
);
if (!success) revert SetupFailed();
}
// solhint-disable-next-line no-empty-blocks
function contractId() internal pure virtual returns (bytes32) {}
function implementation() public view returns (address implementation_) {
// solhint-disable-next-line no-inline-assembly
assembly {
implementation_ := sload(_IMPLEMENTATION_SLOT)
}
}
// solhint-disable-next-line no-empty-blocks
function setup(bytes calldata data) public {}
// solhint-disable-next-line no-complex-fallback
fallback() external payable {
address implementaion_ = implementation();
// solhint-disable-next-line no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
receive() external payable virtual {
revert EtherNotAccepted();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '../interfaces/IUpgradable.sol';
abstract contract Upgradable is IUpgradable {
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
// keccak256('owner')
bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
modifier onlyOwner() {
if (owner() != msg.sender) revert NotOwner();
_;
}
function owner() public view returns (address owner_) {
// solhint-disable-next-line no-inline-assembly
assembly {
owner_ := sload(_OWNER_SLOT)
}
}
function transferOwnership(address newOwner) external virtual onlyOwner {
if (newOwner == address(0)) revert InvalidOwner();
emit OwnershipTransferred(newOwner);
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(_OWNER_SLOT, newOwner)
}
}
function implementation() public view returns (address implementation_) {
// solhint-disable-next-line no-inline-assembly
assembly {
implementation_ := sload(_IMPLEMENTATION_SLOT)
}
}
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external override onlyOwner {
if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId())
revert InvalidImplementation();
if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
if (params.length > 0) {
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));
if (!success) revert SetupFailed();
}
emit Upgraded(newImplementation);
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(_IMPLEMENTATION_SLOT, newImplementation)
}
}
function setup(bytes calldata data) external override {
// Prevent setup from being called on the implementation
if (implementation() == address(0)) revert NotProxy();
_setup(data);
}
// solhint-disable-next-line no-empty-blocks
function _setup(bytes calldata data) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}pragma solidity >=0.6.2;
interface IPangolinRouter {
function factory() external pure returns (address);
function WAVAX() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityAVAX(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountAVAXMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountAVAX, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityAVAX(
address token,
uint liquidity,
uint amountTokenMin,
uint amountAVAXMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountAVAX);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityAVAXWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountAVAXMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountAVAX);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactAVAXForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactAVAX(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForAVAX(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapAVAXForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
function removeLiquidityAVAXSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountAVAXMin,
address to,
uint deadline
) external returns (uint amountAVAX);
function removeLiquidityAVAXWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountAVAXMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountAVAX);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactAVAXForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForAVAXSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}// SPDX-License-Identifier: UNLICENSED pragma solidity >0.0.0; import '@pangolindex/exchange-contracts/contracts/pangolin-periphery/interfaces/IPangolinRouter.sol';
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IRoledPausable {
event PauserProposed(address indexed currentPauser, address indexed pendingPauser);
event PauserUpdated(address indexed pendingPauser);
event Paused();
event Unpaused();
error ContractIsPaused();
error NotPauser();
error NotPendingPauser();
function updatePauser(address _newPauser) external;
function acceptPauser() external;
function pause() external;
function unpause() external;
function paused() external view returns (bool value);
function pauser() external view returns (address value);
function pendingPauser() external view returns (address value);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface ISquidFeeCollector {
event FeeCollected(address token, address integrator, uint256 squidFee, uint256 integratorFee);
event FeeWithdrawn(address token, address account, uint256 amount);
error TransferFailed();
error ExcessiveIntegratorFee();
function collectFee(
address token,
uint256 amountToTax,
address integratorAddress,
uint256 integratorFee
) external;
function withdrawFee(address token) external;
function getBalance(address token, address account) external view returns (uint256 accountBalance);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface ISquidMulticall {
enum CallType {
Default,
FullTokenBalance,
FullNativeBalance,
CollectTokenBalance
}
struct Call {
CallType callType;
address target;
uint256 value;
bytes callData;
bytes payload;
}
error AlreadyRunning();
error CallFailed(uint256 callPosition, bytes reason);
function run(Call[] calldata calls) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {ISquidMulticall} from "./ISquidMulticall.sol";
interface ISquidRouter {
event CrossMulticallExecuted(bytes32 indexed payloadHash);
event CrossMulticallFailed(bytes32 indexed payloadHash, bytes reason, address indexed refundRecipient);
function bridgeCall(
string calldata destinationChain,
string calldata bridgedTokenSymbol,
uint256 amount,
ISquidMulticall.Call[] calldata calls,
address refundRecipient,
bool forecallEnabled
) external payable;
function callBridge(
address token,
uint256 amount,
string calldata destinationChain,
string calldata destinationAddress,
string calldata bridgedTokenSymbol,
ISquidMulticall.Call[] calldata calls
) external payable;
function callBridgeCall(
address token,
uint256 amount,
string calldata destinationChain,
string calldata bridgedTokenSymbol,
ISquidMulticall.Call[] calldata sourceCalls,
ISquidMulticall.Call[] calldata destinationCalls,
address refundRecipient,
bool forecallEnabled
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library StorageSlot {
function setUint256(bytes32 slot, uint256 value) internal {
assembly {
sstore(slot, value)
}
}
function getUint256(bytes32 slot) internal view returns (uint256 value) {
assembly {
value := sload(slot)
}
}
function setAddress(bytes32 slot, address value) internal {
assembly {
sstore(slot, value)
}
}
function getAddress(bytes32 slot) internal view returns (address value) {
assembly {
value := sload(slot)
}
}
function setBool(bytes32 slot, bool value) internal {
assembly {
sstore(slot, value)
}
}
function getBool(bytes32 slot) internal view returns (bool value) {
assembly {
value := sload(slot)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {IRoledPausable} from "./interfaces/IRoledPausable.sol";
import {StorageSlot} from "./libraries/StorageSlot.sol";
abstract contract RoledPausable is IRoledPausable {
using StorageSlot for bytes32;
bytes32 internal constant PAUSED_SLOT = keccak256("RoledPausable.paused");
bytes32 internal constant PAUSER_SLOT = keccak256("RoledPausable.pauser");
bytes32 internal constant PENDING_PAUSER_SLOT = keccak256("RoledPausable.pendingPauser");
modifier whenNotPaused() {
if (paused()) revert ContractIsPaused();
_;
}
modifier onlyPauser() {
if (msg.sender != pauser()) revert NotPauser();
_;
}
constructor() {
_setPauser(msg.sender);
}
function updatePauser(address newPauser) external onlyPauser {
PENDING_PAUSER_SLOT.setAddress(newPauser);
emit PauserProposed(msg.sender, newPauser);
}
function acceptPauser() external {
if (msg.sender != pendingPauser()) revert NotPendingPauser();
_setPauser(msg.sender);
PENDING_PAUSER_SLOT.setAddress(address(0));
}
function pause() external virtual onlyPauser {
PAUSED_SLOT.setBool(true);
emit Paused();
}
function unpause() external virtual onlyPauser {
PAUSED_SLOT.setBool(false);
emit Unpaused();
}
function pauser() public view returns (address value) {
value = PAUSER_SLOT.getAddress();
}
function paused() public view returns (bool value) {
value = PAUSED_SLOT.getBool();
}
function pendingPauser() public view returns (address value) {
value = PENDING_PAUSER_SLOT.getAddress();
}
function _setPauser(address _pauser) internal {
PAUSER_SLOT.setAddress(_pauser);
emit PauserUpdated(_pauser);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {Upgradable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradables/Upgradable.sol";
import {ISquidFeeCollector} from "./interfaces/ISquidFeeCollector.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract SquidFeeCollector is ISquidFeeCollector, Upgradable {
bytes32 private constant BALANCES_PREFIX = keccak256("SquidFeeCollector.balances");
bytes32 private constant SPECIFIC_FEES_PREFIX = keccak256("SquidFeeCollector.specificFees");
address public immutable squidTeam;
// Value expected with 2 decimals
/// eg. 825 is 8.25%
uint256 public immutable squidDefaultFee;
error ZeroAddressProvided();
constructor(address _squidTeam, uint256 _squidDefaultFee) {
if (_squidTeam == address(0)) revert ZeroAddressProvided();
squidTeam = _squidTeam;
squidDefaultFee = _squidDefaultFee;
}
/// @param integratorFee Value expected with 2 decimals
/// eg. 825 is 8.25%
function collectFee(
address token,
uint256 amountToTax,
address integratorAddress,
uint256 integratorFee
) external {
if (integratorFee > 1000) revert ExcessiveIntegratorFee();
uint256 specificFee = getSpecificFee(integratorAddress);
uint256 squidFee = specificFee == 0 ? squidDefaultFee : specificFee;
uint256 baseFeeAmount = (amountToTax * integratorFee) / 10000;
uint256 squidFeeAmount = (baseFeeAmount * squidFee) / 10000;
uint256 integratorFeeAmount = baseFeeAmount - squidFeeAmount;
_safeTransferFrom(token, msg.sender, baseFeeAmount);
_setBalance(token, squidTeam, getBalance(token, squidTeam) + squidFeeAmount);
_setBalance(token, integratorAddress, getBalance(token, integratorAddress) + integratorFeeAmount);
emit FeeCollected(token, integratorAddress, squidFeeAmount, integratorFeeAmount);
}
function withdrawFee(address token) external {
uint256 balance = getBalance(token, msg.sender);
_setBalance(token, msg.sender, 0);
_safeTransfer(token, msg.sender, balance);
emit FeeWithdrawn(token, msg.sender, balance);
}
function setSpecificFee(address integrator, uint256 fee) external onlyOwner {
bytes32 slot = _computeSpecificFeeSlot(integrator);
assembly {
sstore(slot, fee)
}
}
function getBalance(address token, address account) public view returns (uint256 value) {
bytes32 slot = _computeBalanceSlot(token, account);
assembly {
value := sload(slot)
}
}
function getSpecificFee(address integrator) public view returns (uint256 value) {
bytes32 slot = _computeSpecificFeeSlot(integrator);
assembly {
value := sload(slot)
}
}
function contractId() external pure returns (bytes32 id) {
id = keccak256("squid-fee-collector");
}
function _setBalance(
address token,
address account,
uint256 amount
) private {
bytes32 slot = _computeBalanceSlot(token, account);
assembly {
sstore(slot, amount)
}
}
function _computeBalanceSlot(address token, address account) private pure returns (bytes32 slot) {
slot = keccak256(abi.encodePacked(BALANCES_PREFIX, token, account));
}
function _computeSpecificFeeSlot(address integrator) private pure returns (bytes32 slot) {
slot = keccak256(abi.encodePacked(SPECIFIC_FEES_PREFIX, integrator));
}
function _safeTransferFrom(
address token,
address from,
uint256 amount
) internal {
(bool success, bytes memory returnData) = token.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, address(this), amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || token.code.length == 0) revert TransferFailed();
}
function _safeTransfer(
address token,
address to,
uint256 amount
) internal {
(bool success, bytes memory returnData) = token.call(
abi.encodeWithSelector(IERC20.transfer.selector, to, amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || token.code.length == 0) revert TransferFailed();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {Proxy} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradables/Proxy.sol";
contract SquidFeeCollectorProxy is Proxy {
function contractId() internal pure override returns (bytes32 id) {
id = keccak256("squid-fee-collector");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {ISquidMulticall} from "./interfaces/ISquidMulticall.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract SquidMulticall is ISquidMulticall {
bool private isRunning;
error TransferFailed();
function run(Call[] calldata calls) external payable {
// Prevents reentrancy
if (isRunning) revert AlreadyRunning();
isRunning = true;
for (uint256 i = 0; i < calls.length; i++) {
Call memory call = calls[i];
if (call.callType == CallType.FullTokenBalance) {
(address token, uint256 amountParameterPosition) = abi.decode(call.payload, (address, uint256));
uint256 amount = IERC20(token).balanceOf(address(this));
_setCallDataParameter(call.callData, amountParameterPosition, amount);
} else if (call.callType == CallType.FullNativeBalance) {
call.value = address(this).balance;
} else if (call.callType == CallType.CollectTokenBalance) {
address token = abi.decode(call.payload, (address));
_safeTransferFrom(token, msg.sender, IERC20(token).balanceOf(msg.sender));
continue;
}
(bool success, bytes memory data) = call.target.call{value: call.value}(call.callData);
if (!success) revert CallFailed(i, data);
}
isRunning = false;
}
function _safeTransferFrom(
address token,
address from,
uint256 amount
) internal {
(bool success, bytes memory returnData) = token.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, address(this), amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || token.code.length == 0) revert TransferFailed();
}
function _setCallDataParameter(
bytes memory callData,
uint256 parameterPosition,
uint256 value
) private pure {
assembly {
// 36 bytes shift because 32 for prefix + 4 for selector
mstore(add(callData, add(36, mul(parameterPosition, 32))), value)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {ISquidRouter} from "./interfaces/ISquidRouter.sol";
import {ISquidMulticall} from "./interfaces/ISquidMulticall.sol";
import {AxelarForecallable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/executables/AxelarForecallable.sol";
import {IAxelarGasService} from "@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol";
import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol";
import {AddressToString} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/StringAddressUtils.sol";
import {Upgradable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradables/Upgradable.sol";
import {RoledPausable} from "./RoledPausable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract SquidRouter is ISquidRouter, AxelarForecallable, Upgradable, RoledPausable {
using AddressToString for address;
IAxelarGasService private immutable gasService;
IAxelarGasService private immutable forecallGasService;
ISquidMulticall private immutable squidMulticall;
error ZeroAddressProvided();
constructor(
address _gateway,
address _gasService,
address _forecallGasService,
address _multicall
) AxelarForecallable(_gateway) {
if (
_gateway == address(0) ||
_gasService == address(0) ||
_forecallGasService == address(0) ||
_multicall == address(0)
) revert ZeroAddressProvided();
gasService = IAxelarGasService(_gasService);
forecallGasService = IAxelarGasService(_forecallGasService);
squidMulticall = ISquidMulticall(_multicall);
}
function bridgeCall(
string calldata destinationChain,
string calldata bridgedTokenSymbol,
uint256 amount,
ISquidMulticall.Call[] calldata calls,
address refundRecipient,
bool enableForecall
) external payable whenNotPaused {
address bridgedTokenAddress = gateway.tokenAddresses(bridgedTokenSymbol);
_safeTransferFrom(bridgedTokenAddress, msg.sender, amount);
_bridgeCall(destinationChain, bridgedTokenSymbol, bridgedTokenAddress, calls, refundRecipient, enableForecall);
}
function callBridge(
address token,
uint256 amount,
string calldata destinationChain,
string calldata destinationAddress,
string calldata bridgedTokenSymbol,
ISquidMulticall.Call[] calldata calls
) external payable whenNotPaused {
fundAndRunMulticall(token, amount, calls);
address bridgedTokenAddress = gateway.tokenAddresses(bridgedTokenSymbol);
uint256 bridgedTokenAmount = IERC20(bridgedTokenAddress).balanceOf(address(this));
_approve(bridgedTokenAddress, address(gateway), bridgedTokenAmount);
gateway.sendToken(destinationChain, destinationAddress, bridgedTokenSymbol, bridgedTokenAmount);
}
function callBridgeCall(
address token,
uint256 amount,
string calldata destinationChain,
string calldata bridgedTokenSymbol,
ISquidMulticall.Call[] calldata sourceCalls,
ISquidMulticall.Call[] calldata destinationCalls,
address refundRecipient,
bool enableForecall
) external payable whenNotPaused {
fundAndRunMulticall(token, amount, sourceCalls);
address bridgedTokenAddress = gateway.tokenAddresses(bridgedTokenSymbol);
_bridgeCall(
destinationChain,
bridgedTokenSymbol,
bridgedTokenAddress,
destinationCalls,
refundRecipient,
enableForecall
);
}
function contractId() external pure override returns (bytes32 id) {
id = keccak256("squid-router");
}
function fundAndRunMulticall(
address token,
uint256 amount,
ISquidMulticall.Call[] memory calls
) public payable whenNotPaused {
uint256 valueToSend;
if (token == address(0)) {
valueToSend = amount;
} else {
_transferTokenToMulticall(token, amount);
}
squidMulticall.run{value: valueToSend}(calls);
}
function _executeWithToken(
string calldata,
string calldata,
bytes calldata payload,
string calldata bridgedTokenSymbol,
uint256
) internal override {
(ISquidMulticall.Call[] memory calls, address refundRecipient) = abi.decode(
payload,
(ISquidMulticall.Call[], address)
);
address bridgedTokenAddress = gateway.tokenAddresses(bridgedTokenSymbol);
uint256 contractBalance = IERC20(bridgedTokenAddress).balanceOf(address(this));
_approve(bridgedTokenAddress, address(squidMulticall), contractBalance);
try squidMulticall.run(calls) {
emit CrossMulticallExecuted(keccak256(payload));
} catch (bytes memory reason) {
// Refund tokens to refund recepient if swap fails
_safeTransfer(bridgedTokenAddress, refundRecipient, contractBalance);
emit CrossMulticallFailed(keccak256(payload), reason, refundRecipient);
}
}
function _bridgeCall(
string calldata destinationChain,
string calldata bridgedTokenSymbol,
address bridgedTokenAddress,
ISquidMulticall.Call[] calldata calls,
address refundRecipient,
bool enableForecall
) private {
if (refundRecipient == address(0)) revert ZeroAddressProvided();
bytes memory payload = abi.encode(calls, refundRecipient);
// Only works if destination router has same address
string memory destinationContractAddress = address(this).toString();
uint256 bridgedTokenBalance = IERC20(bridgedTokenAddress).balanceOf(address(this));
if (address(this).balance > 0) {
IAxelarGasService executionService = enableForecall ? forecallGasService : gasService;
executionService.payNativeGasForContractCallWithToken{value: address(this).balance}(
address(this),
destinationChain,
destinationContractAddress,
payload,
bridgedTokenSymbol,
bridgedTokenBalance,
refundRecipient
);
}
_approve(bridgedTokenAddress, address(gateway), bridgedTokenBalance);
gateway.callContractWithToken(
destinationChain,
destinationContractAddress,
payload,
bridgedTokenSymbol,
bridgedTokenBalance
);
}
function _approve(
address tokenAddress,
address spender,
uint256 amount
) private {
if (IERC20(tokenAddress).allowance(address(this), spender) < amount) {
// Not a security issue since the contract doesn't store tokens
IERC20(tokenAddress).approve(spender, type(uint256).max);
}
}
function _transferTokenToMulticall(address token, uint256 amount) private {
(bool success, bytes memory returnData) = token.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, msg.sender, address(squidMulticall), amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || token.code.length == 0) revert TransferFailed();
}
function _setup(bytes calldata data) internal override {
address _pauser = abi.decode(data, (address));
if (_pauser == address(0)) revert("Invalid pauser address");
_setPauser(_pauser);
}
}{
"optimizer": {
"enabled": true,
"runs": 99999
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"EtherNotAccepted","type":"error"},{"inputs":[],"name":"InvalidImplementation","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"SetupFailed","type":"error"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"implementation_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"implementationAddress","type":"address"},{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6080806040523461003957337f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c05561069a908161003f8239f35b600080fdfe6080604052600436101561002c575b361561001f575b61001d6105f7565b005b610027610639565b610015565b6000803560e01c908163378dfd8e1461006b575080635c60da1b1461006257639ded06df0361000e5761005d61029f565b61000e565b5061005d61022d565b346101185760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610118576100a261011b565b6100aa610143565b6044359067ffffffffffffffff8211610114573660238301121561011457816004013592846100d8856101e4565b936100e66040519586610196565b8585523660248783010111610110578561010d9660246020930183880137850101526103b8565b80f35b5080fd5b8380fd5b80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013e57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361013e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101d757604052565b6101df610166565b604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209267ffffffffffffffff8111610220575b01160190565b610228610166565b61021a565b503461013e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013e5760207f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b503461013e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013e5760043567ffffffffffffffff80821161013e573660238301121561013e57816004013590811161013e573691016024011161013e57005b9081602091031261013e575190565b506040513d6000823e3d90fd5b60208082528251818301819052939260005b858110610374575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201610334565b3d156103b3573d90610399826101e4565b916103a76040519384610196565b82523d6000602084013e565b606090565b91909173ffffffffffffffffffffffffffffffffffffffff917f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0938385541633036105cd577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc93808554166105a357600460207fc097d45e5a99ca772ab5ec2e5457c2e249760944b95b0b97cbb6b03ec55bae8492604051928380927f8291286c00000000000000000000000000000000000000000000000000000000825289165afa908115610596575b600091610568575b500361053e576000948386955555604051610500816104d460208201947f9ded06df00000000000000000000000000000000000000000000000000000000865260248301610322565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610196565b51915af461050c610388565b501561051457565b60046040517f97905dfb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f68155f9a000000000000000000000000000000000000000000000000000000008152fd5b610589915060203d811161058f575b6105818183610196565b810190610306565b3861048b565b503d610577565b61059e610315565b610483565b60046040517f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546000808092368280378136915af43d82803e15610635573d90f35b3d90fd5b5060046040517f37334834000000000000000000000000000000000000000000000000000000008152fdfea26469706673582212205a1ae4e4554ee5e5b30712df541f3571c30f56cc0963334dec2abbb4f5176f4d64736f6c63430008110033
Deployed Bytecode
0x6080604052600436101561002c575b361561001f575b61001d6105f7565b005b610027610639565b610015565b6000803560e01c908163378dfd8e1461006b575080635c60da1b1461006257639ded06df0361000e5761005d61029f565b61000e565b5061005d61022d565b346101185760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610118576100a261011b565b6100aa610143565b6044359067ffffffffffffffff8211610114573660238301121561011457816004013592846100d8856101e4565b936100e66040519586610196565b8585523660248783010111610110578561010d9660246020930183880137850101526103b8565b80f35b5080fd5b8380fd5b80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013e57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361013e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101d757604052565b6101df610166565b604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209267ffffffffffffffff8111610220575b01160190565b610228610166565b61021a565b503461013e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013e5760207f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b503461013e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013e5760043567ffffffffffffffff80821161013e573660238301121561013e57816004013590811161013e573691016024011161013e57005b9081602091031261013e575190565b506040513d6000823e3d90fd5b60208082528251818301819052939260005b858110610374575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201610334565b3d156103b3573d90610399826101e4565b916103a76040519384610196565b82523d6000602084013e565b606090565b91909173ffffffffffffffffffffffffffffffffffffffff917f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0938385541633036105cd577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc93808554166105a357600460207fc097d45e5a99ca772ab5ec2e5457c2e249760944b95b0b97cbb6b03ec55bae8492604051928380927f8291286c00000000000000000000000000000000000000000000000000000000825289165afa908115610596575b600091610568575b500361053e576000948386955555604051610500816104d460208201947f9ded06df00000000000000000000000000000000000000000000000000000000865260248301610322565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610196565b51915af461050c610388565b501561051457565b60046040517f97905dfb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f68155f9a000000000000000000000000000000000000000000000000000000008152fd5b610589915060203d811161058f575b6105818183610196565b810190610306565b3861048b565b503d610577565b61059e610315565b610483565b60046040517f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546000808092368280378136915af43d82803e15610635573d90f35b3d90fd5b5060046040517f37334834000000000000000000000000000000000000000000000000000000008152fdfea26469706673582212205a1ae4e4554ee5e5b30712df541f3571c30f56cc0963334dec2abbb4f5176f4d64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$3,565.12
Net Worth in POL
Token Allocations
ETH
84.65%
BSC-USD
15.26%
BNB
0.08%
Others
0.01%
Multichain Portfolio | 35 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.