Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 16852023 | 322 days ago | 0 ETH | ||||
| 16852023 | 322 days ago | 0 ETH | ||||
| 16852022 | 322 days ago | 0 ETH | ||||
| 16851888 | 322 days ago | 0 ETH | ||||
| 16851888 | 322 days ago | 0 ETH | ||||
| 16851887 | 322 days ago | 0 ETH | ||||
| 16851510 | 322 days ago | 0 ETH | ||||
| 16851499 | 322 days ago | 0 ETH | ||||
| 16851469 | 322 days ago | 0 ETH | ||||
| 16851465 | 322 days ago | 0 ETH | ||||
| 16851440 | 322 days ago | 0 ETH | ||||
| 16851181 | 322 days ago | 0 ETH | ||||
| 16851048 | 322 days ago | 0 ETH | ||||
| 16850987 | 322 days ago | 0 ETH | ||||
| 16850975 | 322 days ago | 0 ETH | ||||
| 16850965 | 322 days ago | 0 ETH | ||||
| 16850956 | 322 days ago | 0 ETH | ||||
| 16850935 | 322 days ago | 0 ETH | ||||
| 16850926 | 322 days ago | 0 ETH | ||||
| 16850917 | 322 days ago | 0 ETH | ||||
| 16850916 | 322 days ago | 0 ETH | ||||
| 16850916 | 322 days ago | 0 ETH | ||||
| 16850915 | 322 days ago | 0 ETH | ||||
| 16850913 | 322 days ago | 0 ETH | ||||
| 16850897 | 322 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SwapRequestImpl
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import {IBungeeExecutor} from "../interfaces/IBungeeExecutor.sol";
import {Request, SwapExec} from "../common/SwapRequestStructs.sol";
import {AuthenticationLib} from "../lib/AuthenticationLib.sol";
import {AffiliateFeesLib} from "../lib/AffiliateFeesLib.sol";
import {RequestLib} from "../lib/SwapRequestLib.sol";
import {MofaSignatureInvalid, MinOutputNotMet, InvalidMultipleNativeTokens} from "../common/BungeeErrors.sol";
import {Permit2Lib} from "../lib/Permit2Lib.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {BungeeEvents} from "../common/BungeeEvents.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {IFeeCollector} from "../interfaces/IFeeCollector.sol";
import {BungeeGatewayBase} from "./BungeeGatewayBase.sol";
import {BungeeGatewayStorage} from "./BungeeGatewayStorage.sol";
contract SwapRequestImpl is BungeeGatewayStorage, BungeeGatewayBase, BungeeEvents {
using RequestLib for Request;
using RequestLib for SwapExec[];
using SafeTransferLib for ERC20;
constructor(address _owner, address _permit2) BungeeGatewayStorage(_owner, _permit2) {}
/*//////////////////////////////////////////////////////////////////////////
SOURCE FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice extract the user requests and routes it via the respetive routers.
* @notice the user requests can only be extracted if the mofa signature is valid.
* @notice each request can be routed via a different router.
* @notice it would be assumed as a successful execution if the router call does not revert.
* @dev state of the request would be saved against the requesthash created.
* @dev funds from the user wallet will be pulled and sent to the router.
* @dev if there is a swap involved then swapped funds would reach the router.
* @param swapExecs batch of extractions submitted by the transmitter.
* @param mofaSignature signature of mofa on the batch.
*/
function extractAndSwap(SwapExec[] calldata swapExecs, bytes calldata mofaSignature) external payable {
// Checks if batch has been authorised by MOFA
_checkMofaSig(swapExecs, mofaSignature);
// Iterate through swapExec
unchecked {
for (uint256 i = 0; i < swapExecs.length; i++) {
SwapExec memory exec = swapExecs[i];
// Preventing multiple native tokens
bool isNativeTokenUsed = false;
// Check if the promised amount is more than the minOutputAmount
for (uint256 j = 0; j < exec.request.basicReq.outputTokens.length; j++) {
if (exec.fulfilAmounts[j] < exec.request.basicReq.minOutputAmounts[j]) revert MinOutputNotMet();
// Check if native token has already been used as an output token
if (exec.request.basicReq.outputTokens[j] == NATIVE_TOKEN_ADDRESS) {
if (isNativeTokenUsed) revert InvalidMultipleNativeTokens();
isNativeTokenUsed = true;
}
}
// Create the request hash for the submitted request.
bytes32 requestHash = exec.request.hashRequest();
// If swap payload is present solver wants to use user funds to perform swap
// If swap payload is not present then output tokens are directly transferred from solver
if (exec.swapPayload.length > 0) {
_swapRequestExternal(requestHash, exec);
} else {
_fulfilRequest(requestHash, exec);
}
// calldata execution via Calldata Executor using Request.destinationPayload, Request.minDestGas
_executeCalldata(
exec.request.basicReq.receiver,
exec.request.minDestGas,
exec.fulfilAmounts,
exec.request.basicReq.outputTokens,
requestHash,
exec.request.destinationPayload
);
}
}
}
/*//////////////////////////////////////////////////////////////////////////
INTERNAL SOURCE FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice checks if the mofa signature is valid on the batch submitted by the transmitter.
* @param swapExecs batch of extractions submitted by the transmitter.
* @param mofaSignature signature of mofa on the batch.
*/
function _checkMofaSig(SwapExec[] calldata swapExecs, bytes memory mofaSignature) internal view {
// Create the hash of BatchHash
bytes32 batchHash = swapExecs.hashBatch();
// Get the signer
address signer = AuthenticationLib.authenticate(batchHash, mofaSignature);
// Check if addresses match
if (signer != MOFA_SIGNER) revert MofaSignatureInvalid();
}
/**
* @dev collects unlocked fee in input token and registers it with the FeeCollector
*/
function _collectFee(address token, uint256 amount, address feeTaker) internal {
_sendFundsFromContract(token, amount, address(FEE_COLLECTOR));
IFeeCollector(FEE_COLLECTOR).registerFee(feeTaker, amount, token);
}
/**
* @notice this function is used when the transmitter submits a swap for a user request.
* @notice assumption is that the receiver of the swap will be the router mentioned in the exec.
* @dev Funds would be transferred to the swap executor first.
* @dev Swap executor will be called with the swap payload.
* @dev Funds after the swap should reach directly to the user
* @dev If the fulfilAmounts are not met, the transaction will revert.
* @param swapExec execution submitted by the transmitter for the request.
*/
function _swapRequestExternal(bytes32 requestHash, SwapExec memory swapExec) internal {
// Calls Permit2 to transfer funds from user to swap executor.
PERMIT2.permitWitnessTransferFrom(
Permit2Lib.toPermit(
swapExec.request.basicReq.inputToken,
swapExec.request.basicReq.inputAmount,
swapExec.request.basicReq.nonce,
swapExec.request.basicReq.deadline
),
/// @dev transfer tokens to SwapExecutor
Permit2Lib.transferDetails(swapExec.request.basicReq.inputAmount, address(SWAP_EXECUTOR)),
swapExec.request.basicReq.sender,
requestHash,
RequestLib.PERMIT2_ORDER_TYPE,
swapExec.userSignature
);
// Check output token balances of receiver before swap
uint256[] memory initialBalances = new uint256[](swapExec.request.basicReq.outputTokens.length);
for (uint256 i = 0; i < swapExec.request.basicReq.outputTokens.length; i++) {
if (swapExec.request.basicReq.outputTokens[i] == NATIVE_TOKEN_ADDRESS) {
initialBalances[i] = swapExec.request.basicReq.receiver.balance;
} else {
initialBalances[i] = ERC20(swapExec.request.basicReq.outputTokens[i]).balanceOf(
swapExec.request.basicReq.receiver
);
}
}
// Check if fee is supposed to be deducted
/// @dev fee has to be deducted from input token since swap may be for multiple output tokens
(, uint256 feeAmount, address feeTaker) = AffiliateFeesLib.getAffiliateFees(
swapExec.request.basicReq.inputAmount,
swapExec.request.affiliateFees
);
// Call the swap executor to execute the swap.
/// @dev swap output tokens are expected to be sent directly to the user
/// @dev expects swapPayload to perform a single, but multi output swap
if (feeAmount > 0) {
// Collect fee and execute swap
SWAP_EXECUTOR.collectFeeAndExecuteSwap(
swapExec.request.basicReq.inputToken,
swapExec.request.basicReq.inputAmount,
swapExec.swapRouter,
swapExec.swapPayload,
FEE_COLLECTOR,
feeTaker,
feeAmount
);
} else {
SWAP_EXECUTOR.executeSwap(
swapExec.request.basicReq.inputToken,
swapExec.request.basicReq.inputAmount,
swapExec.swapRouter,
swapExec.swapPayload
);
}
/// @dev fulfilAmounts are expected to be sent directly to user by the swap router
// Get the final balances of receiver and check if the fulfilAmounts were met
for (uint256 i = 0; i < swapExec.request.basicReq.outputTokens.length; i++) {
uint256 finalBalance;
if (swapExec.request.basicReq.outputTokens[i] == NATIVE_TOKEN_ADDRESS) {
finalBalance = swapExec.request.basicReq.receiver.balance;
} else {
finalBalance = ERC20(swapExec.request.basicReq.outputTokens[i]).balanceOf(
swapExec.request.basicReq.receiver
);
}
// Check if the fulfilAmounts were met
if (finalBalance - initialBalances[i] < swapExec.fulfilAmounts[i]) revert MinOutputNotMet();
}
emit RequestFulfilled(requestHash, SWAP_REQUEST_IMPL_ID, msg.sender, abi.encode(swapExec));
}
/**
* @notice this function is used when the transmitter submits a request that does not involve a swap.
* @dev funds would be transferred to the router directly from the user.
* @dev Saves the extraction details against the requestHash.
* @param swapExec execution submitted by the transmitter for the request.
When a request is settled beneficiary will receive funds.
*/
function _fulfilRequest(bytes32 requestHash, SwapExec memory swapExec) internal {
// Calls Permit2 to transfer funds from user to BungeeGateway
PERMIT2.permitWitnessTransferFrom(
Permit2Lib.toPermit(
swapExec.request.basicReq.inputToken,
swapExec.request.basicReq.inputAmount,
swapExec.request.basicReq.nonce,
swapExec.request.basicReq.deadline
),
Permit2Lib.transferDetails(swapExec.request.basicReq.inputAmount, address(this)),
swapExec.request.basicReq.sender,
requestHash,
RequestLib.PERMIT2_ORDER_TYPE,
swapExec.userSignature
);
// Check if fee is supposed to be deducted
(uint256 netInputAmount, uint256 feeAmount, address feeTaker) = AffiliateFeesLib.getAffiliateFees(
swapExec.request.basicReq.inputAmount,
swapExec.request.affiliateFees
);
if (feeAmount > 0) {
// @todo how to register BungeeGateway and SwapExecutor as router
_collectFee(swapExec.request.basicReq.inputToken, feeAmount, feeTaker);
}
// Transfer fulfilAmounts from transmitter to user
unchecked {
for (uint256 i = 0; i < swapExec.fulfilAmounts.length; i++) {
// Send the tokens in the exec to the receiver.
_sendFundsToReceiver({
token: swapExec.request.basicReq.outputTokens[i],
from: msg.sender,
amount: swapExec.fulfilAmounts[i],
to: swapExec.request.basicReq.receiver
});
}
}
// Transfer input amount to beneficiary
_sendFundsFromContract(address(swapExec.request.basicReq.inputToken), netInputAmount, swapExec.beneficiary);
emit RequestFulfilled(requestHash, SWAP_REQUEST_IMPL_ID, msg.sender, abi.encode(swapExec));
}
/// @dev delegates calldata execution to the CalldataExecutor contract
/// @param to destination address
/// @param minDestGasLimit minimum gas limit that should be used for the destination execution
/// @param fulfilledAmounts array of amounts fulfilled on the destination in the request
/// @param outputTokens array of output tokens in the request
/// @param requestHash hash of the request
/// @param executionData calldata to be executed on the destination
function _executeCalldata(
address to,
uint256 minDestGasLimit,
uint256[] memory fulfilledAmounts,
address[] memory outputTokens,
bytes32 requestHash,
bytes memory executionData
) internal {
// @review these checks & encoding must be here or in the CalldataExecutor contract?
// Check and return with no action if the data is empty
// Check and return with no action if the destination is invalid
if (executionData.length == 0 || to == address(0) || to == address(this)) return;
// Encodes request data in the payload
bytes memory encodedData = abi.encodeCall(
// @todo too many hops for destination calldata? BungeeGateway → CalldataExecutor → IBungeeExecutor → Aave deposit
IBungeeExecutor.executeData,
(fulfilledAmounts, requestHash, outputTokens, executionData)
);
// Execute calldata
CALLDATA_EXECUTOR.executeCalldata(to, encodedData, minDestGasLimit);
}
function _receiveMsg(bytes calldata payload) internal override {
// Do nothing, not needed.
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IEIP712 {
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {IEIP712} from "./IEIP712.sol";
/// @title SignatureTransfer
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface ISignatureTransfer is IEIP712 {
/// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
/// @param maxAmount The maximum amount a spender can request to transfer
error InvalidAmount(uint256 maxAmount);
/// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
/// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
error LengthMismatch();
/// @notice Emits an event when the owner successfully invalidates an unordered nonce.
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);
/// @notice The token and amount details for a transfer signed in the permit transfer signature
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}
/// @notice The signed permit message for a single token transfer
struct PermitTransferFrom {
TokenPermissions permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice Specifies the recipient address and amount for batched transfers.
/// @dev Recipients and amounts correspond to the index of the signed token permissions array.
/// @dev Reverts if the requested amount is greater than the permitted signed amount.
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}
/// @notice Used to reconstruct the signed permit message for multiple token transfers
/// @dev Do not need to pass in spender address as it is required that it is msg.sender
/// @dev Note that a user still signs over a spender address
struct PermitBatchTransferFrom {
// the tokens and corresponding amounts permitted for a transfer
TokenPermissions[] permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
/// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
/// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
/// @dev It returns a uint256 bitmap
/// @dev The index, or wordPosition is capped at type(uint248).max
function nonceBitmap(address, uint256) external view returns (uint256);
/// @notice Transfers a token using a signed permit message
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param signature The signature to verify
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers a token using a signed permit message
/// @notice Includes extra data provided by the caller to verify signature over
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param signature The signature to verify
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @notice Includes extra data provided by the caller to verify signature over
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Invalidates the bits specified in mask for the bitmap at the word position
/// @dev The wordPos is maxed at type(uint248).max
/// @param wordPos A number to index the nonceBitmap at
/// @param mask A bitmap masked against msg.sender's current bitmap at the word position
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // error MofaSignatureInvalid(); error InsufficientNativeAmount(); error InvalidMultipleNativeTokens(); error FulfilmentChainInvalid(); error RequestAlreadyFulfilled(); error RouterNotRegistered(); error TransferFailed(); error CallerNotBungeeGateway(); error NoExecutionCacheFound(); error ExecutionCacheFailed(); error SwapOutputInsufficient(); error UnsupportedDestinationChainId(); error MinOutputNotMet(); error OnlyOwner(); error OnlyNominee(); error InvalidRequest(); error FulfilmentDeadlineNotMet(); error CallerNotDelegate(); error BungeeSiblingDoesNotExist(); error InvalidMsg(); error NotDelegate(); error RequestProcessed(); error RequestNotProcessed(); error InvalidSwitchboard(); error PromisedAmountNotMet(); error MsgReceiveFailed(); error RouterAlreadyWhitelisted(); error InvalidStake(); error RouterAlreadyRegistered(); error InvalidFulfil(); error InsufficientCapacity();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract BungeeEvents {
/// @notice Emitted when a request is extracted
/// @param requestHash hash of the request
/// @param transmitter address of the transmitter
/// @param execution encoded execution data
event RequestExtracted(bytes32 indexed requestHash, uint8 implId, address transmitter, bytes execution);
/// @notice Emitted when a request is fulfilled
/// @param requestHash hash of the request
/// @param fulfiller address of the fulfiller
/// @param execution encoded execution data
event RequestFulfilled(bytes32 indexed requestHash, uint8 implId, address fulfiller, bytes execution);
// emitted on the source once settlement completes
/// @param requestHash hash of the request
event RequestSettled(bytes32 indexed requestHash);
// emitted on the destination once settlement completes
event RequestsSettledOnDestination(
bytes32[] requestHashes,
uint8 implId,
address transmitter,
uint256 outboundFees
);
/// @notice Emitted on the originChain when a request is withdrawn beyond fulfilment deadline
/// @param requestHash hash of the request
/// @param token token being withdrawn
/// @param amount amount being withdrawn
/// @param to address of the recipient
event WithdrawOnOrigin(bytes32 indexed requestHash, address token, uint256 amount, address to);
/// @notice Emitted on the destinationChain when a request is withdrawn if transmitter fails to fulfil
/// @param requestHash hash of the request
/// @param token token being withdrawn
/// @param amount amount being withdrawn
/// @param to address of the recipient
event WithdrawOnDestination(bytes32 indexed requestHash, address token, uint256 amount, address to);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
// Basic details in the request
struct BasicRequest {
// src chain id
uint256 originChainId;
// dest chain id
uint256 destinationChainId;
// deadline of the request
uint256 deadline;
// nonce used for uniqueness in signature
uint256 nonce;
// address of the user placing the request.
address sender;
// address of the receiver on destination chain
address receiver;
// delegate address that has some rights over the request signed
address delegate;
// address of bungee gateway, this address will have access to pull funds from the sender.
address bungeeGateway;
// id of the switchboard
uint32 switchboardId;
// address of the input token
address inputToken;
// amount of the input tokens
uint256 inputAmount;
// output token to be received on the destination.
address outputToken;
// minimum amount to be receive on the destination for the output token.
uint256 minOutputAmount;
// native token refuel amount on the destination chain
uint256 refuelAmount;
}
// The Request which user signs
struct Request {
// basic details in the request.
BasicRequest basicReq;
// swap output token that the user is okay with swapping input token to.
address swapOutputToken;
// minimum swap output the user is okay with swapping the input token to.
// Transmitter can choose or not choose to swap tokens.
uint256 minSwapOutput;
// any sort of metadata to be passed with the request
bytes32 metadata;
// fees of the affiliate if any
bytes affiliateFees;
}
// Transmitter's origin chain execution details for a request with promisedAmounts.
struct ExtractExec {
// User signed Request
Request request;
// address of the router being used for the request.
address router;
// promised amount for output token on the destination
uint256 promisedAmount;
// promised amount for native token refuel on the destination
uint256 promisedRefuelAmount;
// RouterPayload (router specific data) + RouterValue (value required by the router) etc etc
bytes routerData;
// swapPayload 0x00 if no swap is involved.
bytes swapPayload;
// swapRouterAddress
address swapRouter;
// user signature against the request
bytes userSignature;
// address of the beneficiary submitted by the transmitter.
// the beneficiary will be the one receiving locked tokens when a request is settled.
address beneficiary;
}
// Transmitter's destination chain execution details with fulfil amounts.
struct FulfilExec {
// User Signed Request
Request request;
// address of the router
address fulfilRouter;
// amount to be sent to the receiver for output token.
uint256 fulfilAmount;
// amount to be sent to the receiver for native token refuel.
uint256 refuelFulfilAmount;
// extraPayload for router.
bytes routerData;
// total msg.value to be sent to fulfil native token output token
uint256 msgValue;
}
struct ExtractedRequest {
uint256 expiry;
address router;
address sender;
address delegate;
uint32 switchboardId;
address token;
address transmitter; // For stake capacity
address beneficiary; // For Transmitter
uint256 amount;
uint256 promisedAmount; // For Transmitter
uint256 promisedRefuelAmount;
bytes affiliateFees; // For integrator
}
struct FulfilledRequest {
uint256 fulfilledAmount;
uint256 fulfilledRefuelAmount;
bool processed;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
// Basic details in the request
struct BasicRequest {
// chain id
uint256 chainId;
// deadline of the request
uint256 deadline;
// nonce used for uniqueness in signature
uint256 nonce;
// address of the user placing the request.
address sender;
// address of the receiver on destination chain
address receiver;
// address of bungee gateway, this address will have access to pull funds from the sender.
address bungeeGateway;
// address of the input token
address inputToken;
// amount of the input tokens
uint256 inputAmount;
// array of output tokens to be received on the destination.
address[] outputTokens;
// array of minimum amounts to be receive on the destination for the output tokens array.
uint256[] minOutputAmounts;
}
// The Request which user signs
struct Request {
// basic details in the request.
BasicRequest basicReq;
// array of addresses to check if request whitelists only certain transmitters
address[] exclusiveTransmitters;
// any sort of metadata to be passed with the request
bytes32 metadata;
// fees of the affiliate if any
bytes affiliateFees;
// calldata execution parameter. Only to be used when execution is required on destination.
// minimum dest gas limit to execute calldata on destination
uint256 minDestGas;
// calldata to be executed on the destination
// calldata can only be executed on the receiver in the request.
bytes destinationPayload;
}
// Transmitter's origin chain execution details for a request with fulfilAmounts.
struct SwapExec {
// User signed Request
Request request;
// array of fulfil amounts for the corresponding output tokens on the destination
uint256[] fulfilAmounts;
// swapPayload 0x00 if no swap is involved.
bytes swapPayload;
// swapRouterAddress
address swapRouter;
// user signature against the request
bytes userSignature;
// address of the beneficiary submitted by the transmitter.
// the beneficiary will be the one receiving locked tokens when a request is settled.
address beneficiary;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import {ERC20, SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {IBaseRouter} from "../interfaces/IBaseRouter.sol";
import {ISwapExecutor} from "../interfaces/ISwapExecutor.sol";
import {ICalldataExecutor} from "../interfaces/ICalldataExecutor.sol";
import {ISwitchboardRouter} from "../interfaces/ISwitchboardRouter.sol";
import {IStakeVault} from "../interfaces/IStakeVault.sol";
import {IFeeCollector} from "../interfaces/IFeeCollector.sol";
import {
RouterAlreadyWhitelisted,
RouterAlreadyRegistered,
TransferFailed,
InvalidStake,
InsufficientCapacity,
InvalidMsg
} from "../common/BungeeErrors.sol";
import {BungeeGatewayStorage} from "./BungeeGatewayStorage.sol";
// @todo should this be renamed to ImplBase. These are implemented by all Impls, not BungeeGateway, but actually acts on BungeeGatewayStorage
abstract contract BungeeGatewayBase is BungeeGatewayStorage {
using SafeTransferLib for ERC20;
/*//////////////////////////////////////////////////////////////////////////
ADMIN FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice send funds to the provided address if stuck, can be called only by owner.
* @param token address of the token
* @param amount hash of the command.
* @param to address, funds will be transferred to this address.
*/
function rescue(address token, address to, uint256 amount) external onlyOwner {
_sendFundsFromContract(token, amount, to);
}
/**
* @notice sets the new mofa signer address.
Can only be called by the owner.
* @param _mofaSigner address of the new mofa signer.
*/
function setMofaSigner(address _mofaSigner) external onlyOwner {
MOFA_SIGNER = _mofaSigner;
}
/**
* @notice sets the new switchboard router.
Can only be called by the owner.
* @param _switchboardRouter address of the new switchboard router.
*/
function setSwitchboardRouter(address _switchboardRouter) external onlyOwner {
SWITCHBOARD_ROUTER = ISwitchboardRouter(_switchboardRouter);
}
/**
* @notice sets the new fee collector.
Can only be called by the owner.
* @param _feeCollector address of the new switchboard router.
*/
function setFeeCollector(address _feeCollector) external onlyOwner {
FEE_COLLECTOR = IFeeCollector(_feeCollector);
}
/**
* @notice sets the new expiry buffer.
Can only be called by the owner.
* @param _expiryBuffer expiry buffer for the request fulfilment deadline.
*/
function setExpiryBuffer(uint256 _expiryBuffer) external onlyOwner {
EXPIRY_BUFFER = _expiryBuffer;
}
/**
* @notice sets the new swap executor contract.
Can only be called by the owner.
* @param _swapExecutor address of the new swap executor.
*/
function setSwapExecutor(address _swapExecutor) external onlyOwner {
SWAP_EXECUTOR = ISwapExecutor(_swapExecutor);
}
/**
* @notice sets the new calldata executor contract.
Can only be called by the owner.
* @param _calldataExecutor address of the new calldata executor.
*/
function setCalldataExecutor(address _calldataExecutor) external onlyOwner {
CALLDATA_EXECUTOR = ICalldataExecutor(_calldataExecutor);
}
/**
* @notice sets the new StakeVault contract.
Can only be called by the owner.
* @param _stakeVault address of the new calldata executor.
*/
function setStakeVault(address _stakeVault) external onlyOwner {
STAKE_VAULT = IStakeVault(_stakeVault);
}
/// @notice register a whitelisted router
function registerWhitelistedRouter(address whitelistedRouter) external onlyOwner {
if (isWhitelisted[whitelistedRouter]) revert RouterAlreadyWhitelisted();
if (bungeeRouters[whitelistedRouter]) revert RouterAlreadyRegistered();
isWhitelisted[whitelistedRouter] = true;
_addBungeeRouter(whitelistedRouter);
}
/// @notice register a staked router
function registerStakedRouter(address stakedRouter) external onlyOwner {
if (bungeeRouters[stakedRouter]) revert RouterAlreadyRegistered();
_addBungeeRouter(stakedRouter);
}
/// @notice Adds a new router to the protocol
function _addBungeeRouter(address _bungeeRouter) internal {
bungeeRouters[_bungeeRouter] = true;
}
function isBungeeRouter(address router) public view returns (bool) {
return bungeeRouters[router];
}
/**
* @notice adds the new whitelisted receiver address against a router.
Can only be called by the owner.
* @param receiver address of the new whitelisted receiver contract.
* @param destinationChainId destination chain id where the receiver will exist.
* @param router router address from which the funs will be routed from.
*/
function setWhitelistedReceiver(address receiver, uint256 destinationChainId, address router) external onlyOwner {
whitelistedReceivers[router][destinationChainId] = receiver;
}
/**
* @notice gets the receiver address set for the router on the destination chain.
* @param destinationChainId destination chain id where the receiver will exist.
* @param router router address from which the funds will be routed from.
*/
function getWhitelistedReceiver(address router, uint256 destinationChainId) external view returns (address) {
return whitelistedReceivers[router][destinationChainId];
}
/**
* @notice Transmitter can register and increment their stake against a token
* @dev Transmitter would transfer their tokens for the stake
*/
function registerTransmitterStake(address token, uint256 capacity) external payable {
transmitterCapacity[msg.sender][token] = transmitterCapacity[msg.sender][token] + capacity;
if (token == NATIVE_TOKEN_ADDRESS) {
if (msg.value != capacity) revert InvalidStake();
(bool success, ) = address(STAKE_VAULT).call{value: capacity, gas: 5000}("");
if (!success) revert TransferFailed();
} else {
ERC20(token).safeTransferFrom(msg.sender, address(STAKE_VAULT), capacity);
}
}
/**
* @notice Transmitter can withdraw their stake against a token
* @dev Transmitter would receive their tokens back
* @dev Transmitter's capacity would be reduced
*/
function withdrawTransmitterStake(address token, uint256 capacity) external {
transmitterCapacity[msg.sender][token] = transmitterCapacity[msg.sender][token] - capacity;
STAKE_VAULT.withdrawStake(token, capacity, msg.sender);
}
function withdrawBeneficiarySettlement(address beneficiary, address router, address token) external {
uint256 amount = beneficiarySettlements[beneficiary][router][token];
if (amount > 0) {
beneficiarySettlements[beneficiary][router][token] = 0;
// Transfer the tokens to the beneficiary
IBaseRouter(router).releaseFunds(token, amount, beneficiary);
}
}
/**
* @notice extract the user requests and routes it via the respetive routers.
* @notice the user requests can only be extracted if the mofa signature is valid.
* @notice each request can be routed via a different router.
* @dev if the switchboard id is not same as the user request, it will revert.
* @dev if the fulfilled amounts is not equal to or greater than the promised amount, revert.
* @dev mark the extracted hash deleted.
* @param payload msg payload sent.
*/
function receiveMsg(bytes calldata payload) external payable {
// If the msg sender is not switchboard router, revert.
if (msg.sender != address(SWITCHBOARD_ROUTER)) revert InvalidMsg();
_receiveMsg(payload);
}
function _receiveMsg(bytes calldata payload) internal virtual {}
/// @notice check capacity for a whitelisted router or staked transmitter
/// @dev if the router is whitelisted, it has a max capacity
/// @dev if the router is not whitelisted, return registered transmitter capacity
function checkCapacity(address transmitter, address token) public view returns (uint256) {
return transmitterCapacity[transmitter][token];
}
function _increaseCapacity(address transmitter, address token, uint256 increaseBy) internal {
transmitterCapacity[transmitter][token] = transmitterCapacity[transmitter][token] + increaseBy;
}
function _reduceCapacity(address transmitter, address token, uint256 reduceBy) internal {
transmitterCapacity[transmitter][token] = transmitterCapacity[transmitter][token] - reduceBy;
}
function _validateAndReduceStake(uint256 inputAmount, address inputToken) internal {
// check capacity before extraction
if (checkCapacity(msg.sender, inputToken) < inputAmount) revert InsufficientCapacity();
_reduceCapacity(msg.sender, inputToken, inputAmount);
}
/**
* @dev send funds to the provided address.
* @param token address of the token
* @param amount hash of the command.
* @param to address, funds will be transferred to this address.
*/
function _sendFundsFromContract(address token, uint256 amount, address to) internal {
/// native token case
if (token == NATIVE_TOKEN_ADDRESS) {
(bool success, ) = to.call{value: amount, gas: 5000}("");
if (!success) revert TransferFailed();
return;
}
/// ERC20 case
ERC20(token).safeTransfer(to, amount);
}
/**
* @dev send funds from an address to the provided address.
* @param token address of the token
* @param from atomic execution.
* @param amount hash of the command.
* @param to address, funds will be transferred to this address.
*/
function _sendFundsToReceiver(address token, address from, uint256 amount, address to) internal {
/// native token case
if (token == NATIVE_TOKEN_ADDRESS) {
(bool success, ) = to.call{value: amount, gas: 5000}("");
if (!success) revert TransferFailed();
return;
}
/// ERC20 case
ERC20(token).safeTransferFrom(from, to, amount);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
import {Ownable} from "../utils/Ownable.sol";
import {ISwapExecutor} from "../interfaces/ISwapExecutor.sol";
import {ICalldataExecutor} from "../interfaces/ICalldataExecutor.sol";
import {ISwitchboardRouter} from "../interfaces/ISwitchboardRouter.sol";
import {IStakeVault} from "../interfaces/IStakeVault.sol";
import {IFeeCollector} from "../interfaces/IFeeCollector.sol";
// SingleOutputRequest
import {
Request as SingleOutputRequest,
ExtractExec as SingleOutputExtractExec,
ExtractedRequest as SingleOutputExtractedRequest,
FulfilledRequest as SingleOutputFulfilledRequest
} from "../common/SingleOutputStructs.sol";
import {RequestLib as SingleOutputRequestLib} from "../lib/SingleOutputRequestLib.sol";
abstract contract BungeeGatewayStorage is Ownable {
using SingleOutputRequestLib for SingleOutputRequest;
using SingleOutputRequestLib for SingleOutputExtractExec;
/// @dev the maximum capacity for whitelisted routers
uint256 internal constant WHITELISTED_MAX_CAPACITY = type(uint256).max;
/// @dev address used to identify native token
address public constant NATIVE_TOKEN_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/// @dev id used to identify single output implementation
uint8 public constant SINGLE_OUTPUT_IMPL_ID = 1;
/// @dev id used to identify swap request implementation
uint8 public constant SWAP_REQUEST_IMPL_ID = 2;
/// @notice address of the permit 2 contract
ISignatureTransfer public immutable PERMIT2;
/// @notice address of the protocol signer
/// @dev this address signs on the request batch that transmitter submits to the protocol.
address public MOFA_SIGNER;
/// @notice address of the SwitchboardRouter
/// @dev BungeeGateway uses this contract to handle cross-chain messages via Socket
ISwitchboardRouter public SWITCHBOARD_ROUTER;
/// @notice address of the SwapExecutor
/// @dev BungeeGateway delegates swap executions to this contract.
ISwapExecutor public SWAP_EXECUTOR;
/// @notice address of the CalldataExecutor
/// @dev BungeeGateway delegates calldata execution at destination chain to this contract.
ICalldataExecutor public CALLDATA_EXECUTOR;
/// @notice address of the FeeCollector
/// @dev BungeeGateway collects fees from the users and transfers them to this contract.
IFeeCollector public FEE_COLLECTOR;
/// @notice address of the StakeVault
/// @dev BungeeGateway transfers all stake to StakeVault
/// @dev BungeeGateway triggers StakeVault to release stake funds
IStakeVault public STAKE_VAULT;
/// @notice this is the buffer time for expiry of any new request
uint256 public EXPIRY_BUFFER;
/// @notice this holds all the requests that have been fulfilled.
mapping(bytes32 requestHash => SingleOutputFulfilledRequest request) internal singleOutputFulfilledRequests;
/// @notice this holds all the requests that have been extracted.
mapping(bytes32 requestHash => SingleOutputExtractedRequest request) internal singleOutputExtractedRequests;
/// @notice this mapping holds all the receiver contracts, these contracts will receive funds.
/// @dev bridged funds would reach receiver contracts first and then transmitter uses these funds to fulfil order.
mapping(address router => mapping(uint256 toChainId => address whitelistedReceiver)) internal whitelistedReceivers;
/// @notice this mapping holds all the addresses that are routers.
/// @dev bungee sends funds from the users to these routers on the origin chain.
/// @dev bungee calls these when fulfilment happens on the destination.
mapping(address routers => bool supported) internal bungeeRouters;
/// @dev this holds all the routers that are whitelisted.
mapping(address router => bool whitelisted) public isWhitelisted;
/// @notice this mapping holds capacity for a transmitter
/// @dev token is checked against the inputToken or swapOutputToken of the request
mapping(address transmitter => mapping(address token => uint256 capacity)) public transmitterCapacity;
/// @notice this mapping stores orders that have been withdrawn on the originChain after Request expiry
/// @dev Requests are deleted from the extractedRequests mapping when withdrawn on the origin chain
/// @dev This mapping stores the withdrawn requests for external contracts to track
mapping(bytes32 requestHash => bool withdrawn) public withdrawnRequests;
/// @notice this mapping stores the settlement amounts for the beneficiaries
/// @dev not all routers would have settlement, so these amounts may not be cleared for some routers
mapping(address beneficiary => mapping(address router => mapping(address token => uint256 amount)))
public beneficiarySettlements;
/**
* @notice Constructor.
* @dev Defines all immutable variables & owner
* @param _owner owner of the contract.
* @param _permit2 address of the permit 2 contract.
*/
constructor(address _owner, address _permit2) Ownable(_owner) {
PERMIT2 = ISignatureTransfer(_permit2);
}
/*//////////////////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////////////////*/
function getSingleOutputExtractedRequest(
bytes32 requestHash
) external view returns (SingleOutputExtractedRequest memory) {
return singleOutputExtractedRequests[requestHash];
}
function getSingleOutputFulfilledRequest(
bytes32 requestHash
) external view returns (SingleOutputFulfilledRequest memory) {
return singleOutputFulfilledRequests[requestHash];
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
interface IBaseRouter {
function releaseFunds(address token, uint256 amount, address recipient) external;
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.17;
interface IBungeeExecutor {
function executeData(
uint256[] calldata amounts,
bytes32 commandHash,
address[] calldata tokens,
bytes memory callData
) external payable;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
interface ICalldataExecutor {
function executeCalldata(address to, bytes memory encodedData, uint256 msgGasLimit) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
interface IFeeCollector {
function registerFee(address feeTaker, uint256 feeAmount, address feeToken) external;
function registerFee(address feeTaker, uint256 feeAmount, address feeToken, bytes32 requestHash) external;
function settleFee(bytes32 requestHash) external;
function refundFee(bytes32 requestHash, address to) external;
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.17;
interface IStakeVault {
function withdrawStake(address token, uint256 capacity, address transmitter) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import {IFeeCollector} from "./IFeeCollector.sol";
interface ISwapExecutor {
function executeSwap(address token, uint256 amount, address swapRouter, bytes memory swapPayload) external;
function executeSwapWithValue(address swapRouter, bytes memory swapPayload, uint256 msgValue) external;
function collectFeeAndExecuteSwap(
address token,
uint256 amount,
address swapRouter,
bytes memory swapPayload,
IFeeCollector feeCollector,
address feeTaker,
uint256 feeAmount
) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
interface ISwitchboardRouter {
function sendOutboundMsg(
uint32 originChainId,
uint32 switchboardId,
uint8 msgId,
uint256 destGasLimit,
bytes calldata payload
) external payable;
function receiveAndDeliverMsg(uint32 switchboardId, uint32 siblingChainId, bytes calldata payload) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.17;
import {ERC20, SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {BytesLib} from "./BytesLib.sol";
/// @notice helpers for AffiliateFees struct
library AffiliateFeesLib {
/// @notice SafeTransferLib - library for safe and optimized operations on ERC20 tokens
using SafeTransferLib for ERC20;
/// @notice error when affiliate fee length is wrong
error WrongAffiliateFeeLength();
/// @notice event emitted when affiliate fee is deducted
event AffiliateFeeDeducted(address feeToken, address feeTakerAddress, uint256 feeAmount);
// Precision used for affiliate fee calculation
uint256 internal constant PRECISION = 10000000000000000;
/**
* @dev calculates & transfers fee to feeTakerAddress
* @param bridgingAmount amount to be bridged
* @param affiliateFees packed bytes containing feeTakerAddress and feeInBps
* ensure the affiliateFees is packed as follows:
* address feeTakerAddress (20 bytes) + uint48 feeInBps (6 bytes) = 26 bytes
* @return bridgingAmount after deducting affiliate fees
*/
function getAffiliateFees(
uint256 bridgingAmount,
bytes memory affiliateFees
) internal pure returns (uint256, uint256, address) {
address feeTakerAddress;
uint256 feeAmount = 0;
if (affiliateFees.length > 0) {
uint48 feeInBps;
if (affiliateFees.length != 26) revert WrongAffiliateFeeLength();
feeInBps = BytesLib.toUint48(affiliateFees, 20);
feeTakerAddress = BytesLib.toAddress(affiliateFees, 0);
if (feeInBps > 0) {
// calculate fee
feeAmount = ((bridgingAmount * feeInBps) / PRECISION);
bridgingAmount -= feeAmount;
}
}
return (bridgingAmount, feeAmount, feeTakerAddress);
}
function getAmountAfterFee(uint256 bridgingAmount, bytes memory affiliateFees) internal pure returns (uint256) {
address feeTakerAddress;
uint256 feeAmount = 0;
if (affiliateFees.length > 0) {
uint48 feeInBps;
if (affiliateFees.length != 26) revert WrongAffiliateFeeLength();
feeInBps = BytesLib.toUint48(affiliateFees, 20);
feeTakerAddress = BytesLib.toAddress(affiliateFees, 0);
if (feeInBps > 0) {
// calculate fee
feeAmount = ((bridgingAmount * feeInBps) / PRECISION);
bridgingAmount -= feeAmount;
}
}
return (bridgingAmount);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
// Library to authenticate the signer address.
library AuthenticationLib {
/// @notice authenticate a message hash signed by Bungee Protocol
/// @param messageHash hash of the message
/// @param signature signature of the message
/// @return true if signature is valid
function authenticate(bytes32 messageHash, bytes memory signature) internal pure returns (address) {
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
return recoverSigner(ethSignedMessageHash, signature);
}
function getEthSignedMessageHash(bytes32 _messageHash) public pure returns (bytes32) {
/*
Signature is produced by signing a keccak256 hash with the following format:
"\x19Ethereum Signed Message\n" + len(msg) + msg
*/
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
}
function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) public pure returns (address) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v) {
require(sig.length == 65, "invalid signature length");
assembly {
/*
First 32 bytes stores the length of the signature
add(sig, 32) = pointer of sig + 32
effectively, skips first 32 bytes of signature
mload(p) loads next 32 bytes starting at the memory address p into memory
*/
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
// implicitly return (r, s, v)
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.4 <0.9.0; library BytesLib { function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint48(bytes memory _bytes, uint256 _start) internal pure returns (uint48) { require(_bytes.length >= _start + 6, "toUint48_outOfBounds"); uint48 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x6), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equal_nonAligned(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let endMinusWord := add(_preBytes, length) let mc := add(_preBytes, 0x20) let cc := add(_postBytes, 0x20) for { // the next line is the loop condition: // while(uint256(mc < endWord) + cb == 2) } eq(add(lt(mc, endMinusWord), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } // Only if still successful // For <1 word tail bytes if gt(success, 0) { // Get the remainder of length/32 // length % 32 = AND(length, 32 - 1) let numTailBytes := and(length, 0x1f) let mcRem := mload(mc) let ccRem := mload(cc) for { let i := 0 // the next line is the loop condition: // while(uint256(i < numTailBytes) + cb == 2) } eq(add(lt(i, numTailBytes), cb), 2) { i := add(i, 1) } { if iszero(eq(byte(i, mcRem), byte(i, ccRem))) { // unsuccess: success := 0 cb := 0 } } } } default { // unsuccess: success := 0 } } return success; } function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
// Library to get Permit 2 related data.
library Permit2Lib {
string public constant TOKEN_PERMISSIONS_TYPE = "TokenPermissions(address token,uint256 amount)";
function toPermit(
address inputToken,
uint256 inputAmount,
uint256 nonce,
uint256 deadline
) internal pure returns (ISignatureTransfer.PermitTransferFrom memory) {
return
ISignatureTransfer.PermitTransferFrom({
permitted: ISignatureTransfer.TokenPermissions({token: inputToken, amount: inputAmount}),
nonce: nonce,
deadline: deadline
});
}
function transferDetails(
uint256 amount,
address spender
) internal pure returns (ISignatureTransfer.SignatureTransferDetails memory) {
return ISignatureTransfer.SignatureTransferDetails({to: spender, requestedAmount: amount});
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.17;
import {BasicRequest, Request, ExtractExec} from "../common/SingleOutputStructs.sol";
import {Permit2Lib} from "./Permit2Lib.sol";
/// @notice helpers for handling BasicRequest
library BasicRequestLib {
bytes internal constant BASIC_REQUEST_TYPE =
abi.encodePacked(
"BasicRequest(",
"uint256 originChainId,",
"uint256 destinationChainId,",
"uint256 deadline,",
"uint256 nonce,",
"address sender,",
"address receiver,",
"address delegate,",
"address bungeeGateway,",
"uint32 switchboardId,",
"address inputToken,",
"uint256 inputAmount,",
"address outputToken,",
"uint256 minOutputAmount,"
"uint256 refuelAmount)"
);
bytes32 internal constant BASIC_REQUEST_TYPE_HASH = keccak256(BASIC_REQUEST_TYPE);
/// @notice Hash of BasicRequest struct on the origin chain
/// @dev enforces originChainId to be the current chainId. Resulting hash would be the same on all chains.
/// @dev helps avoid extra checking of chainId in the contract
/// @param basicReq BasicRequest object to be hashed
function originHash(BasicRequest memory basicReq) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(
BASIC_REQUEST_TYPE_HASH,
abi.encode(
block.chainid,
basicReq.destinationChainId,
basicReq.deadline,
basicReq.nonce,
basicReq.sender,
basicReq.receiver,
basicReq.delegate,
basicReq.bungeeGateway,
basicReq.switchboardId,
basicReq.inputToken,
basicReq.inputAmount,
basicReq.outputToken,
basicReq.minOutputAmount,
basicReq.refuelAmount
)
)
);
}
/// @notice Hash of BasicRequest struct on the destination chain
/// @dev enforces destinationChain to be the current chainId. Resulting hash would be the same on all chains.
/// @dev helps avoid extra checking of chainId in the contract
/// @param basicReq BasicRequest object to be hashed
function destinationHash(BasicRequest memory basicReq) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(
BASIC_REQUEST_TYPE_HASH,
abi.encode(
basicReq.originChainId,
block.chainid,
basicReq.deadline,
basicReq.nonce,
basicReq.sender,
basicReq.receiver,
basicReq.delegate,
basicReq.bungeeGateway,
basicReq.switchboardId,
basicReq.inputToken,
basicReq.inputAmount,
basicReq.outputToken,
basicReq.minOutputAmount,
basicReq.refuelAmount
)
)
);
}
}
/// @title Bungee Request Library.
/// @author bungee protocol
/// @notice This library is responsible for all the hashing related to Request object.
library RequestLib {
using BasicRequestLib for BasicRequest;
// Permit 2 Witness Order Type.
string internal constant PERMIT2_ORDER_TYPE =
string(
abi.encodePacked(
"Request witness)",
abi.encodePacked(BasicRequestLib.BASIC_REQUEST_TYPE, REQUEST_TYPE),
Permit2Lib.TOKEN_PERMISSIONS_TYPE
)
);
// REQUEST TYPE encode packed
bytes internal constant REQUEST_TYPE =
abi.encodePacked(
"Request(",
"BasicRequest basicReq,",
"address swapOutputToken,",
"uint256 minSwapOutput,",
"bytes32 metadata,",
"bytes affiliateFees)"
);
// EXTRACT EXEC TYPE.
bytes internal constant EXTRACT_EXEC_TYPE =
abi.encodePacked(
"ExtractExec(",
"Request request,",
"address router,",
"uint256 promisedAmount,",
"uint256 promisedRefuelAmount,",
"bytes routerData,",
"bytes swapPayload,",
"address swapRouter,",
"bytes userSignature,",
"address beneficiary)"
);
// BUNGEE_REQUEST_TYPE
bytes internal constant BUNGEE_REQUEST_TYPE = abi.encodePacked(REQUEST_TYPE, BasicRequestLib.BASIC_REQUEST_TYPE);
// Keccak Hash of BUNGEE_REQUEST_TYPE
bytes32 internal constant BUNGEE_REQUEST_TYPE_HASH = keccak256(BUNGEE_REQUEST_TYPE);
// Exec Type.
bytes internal constant EXEC_TYPE = abi.encodePacked(EXTRACT_EXEC_TYPE, REQUEST_TYPE);
// Keccak Hash of Exec Type.
bytes32 internal constant EXTRACT_EXEC_TYPE_HASH = keccak256(EXEC_TYPE);
/// @notice Hash of request on the origin chain
/// @param request request that is signe by the user
function hashOriginRequest(Request memory request) internal view returns (bytes32) {
return
keccak256(
abi.encode(
BUNGEE_REQUEST_TYPE_HASH,
request.basicReq.originHash(),
request.swapOutputToken,
request.minSwapOutput,
request.metadata,
keccak256(request.affiliateFees)
)
);
}
/// @notice Hash of request on the destination chain
/// @param request request signed by the user
function hashDestinationRequest(Request memory request) internal view returns (bytes32) {
return
keccak256(
abi.encode(
BUNGEE_REQUEST_TYPE_HASH,
request.basicReq.destinationHash(),
request.swapOutputToken,
request.minSwapOutput,
request.metadata,
keccak256(request.affiliateFees)
)
);
}
/// @notice Hash of Extract Exec on the origin chain
/// @param execution Transmitter submitted extract exec object
function hashOriginExtractExec(ExtractExec memory execution) internal view returns (bytes32) {
return
keccak256(
abi.encode(
EXTRACT_EXEC_TYPE_HASH,
hashOriginRequest(execution.request),
execution.router,
execution.promisedAmount,
execution.promisedRefuelAmount,
keccak256(execution.routerData),
keccak256(execution.swapPayload),
execution.swapRouter,
keccak256(execution.userSignature),
execution.beneficiary
)
);
}
/// @notice hash a batch of extract execs
/// @param extractExecs batch of extract execs to be hashed
function hashOriginBatch(ExtractExec[] memory extractExecs) internal view returns (bytes32) {
unchecked {
bytes32 outputHash = keccak256("BUNGEE_EXTRACT_EXEC");
// Hash all of the extract execs present in the batch.
for (uint256 i = 0; i < extractExecs.length; i++) {
outputHash = keccak256(abi.encode(outputHash, hashOriginExtractExec(extractExecs[i])));
}
return outputHash;
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.17;
import {BasicRequest, Request, SwapExec} from "../common/SwapRequestStructs.sol";
import {Permit2Lib} from "./Permit2Lib.sol";
/// @notice helpers for handling CommandInfo objects
library BasicRequestLib {
bytes internal constant BASIC_REQUEST_TYPE =
abi.encodePacked(
"BasicRequest(",
"uint256 chainId,",
"uint256 deadline,",
"uint256 nonce,",
"address sender,",
"address receiver,",
"address bungeeGateway,",
"address inputToken,",
"uint256 inputAmount,",
"address[] outputTokens,",
"uint256[] minOutputAmounts)"
);
bytes32 internal constant BASIC_REQUEST_TYPE_HASH = keccak256(BASIC_REQUEST_TYPE);
/// @notice Hash of BasicRequest struct on the swap chain
/// @dev enforces chainId to be the current chainId
/// @dev helps avoid extra checking of chainId in the contract
/// @param basicReq BasicRequest object to be hashed
function hash(BasicRequest memory basicReq) internal view returns (bytes32) {
return
keccak256(
abi.encode(
BASIC_REQUEST_TYPE_HASH,
block.chainid,
basicReq.deadline,
basicReq.nonce,
basicReq.sender,
basicReq.receiver,
basicReq.bungeeGateway,
basicReq.inputToken,
basicReq.inputAmount,
keccak256(abi.encodePacked(basicReq.outputTokens)),
keccak256(abi.encodePacked(basicReq.minOutputAmounts))
)
);
}
}
/// @title Bungee Request Library.
/// @author bungee protocol
/// @notice This library is responsible for all the hashing related to Request object.
library RequestLib {
using BasicRequestLib for BasicRequest;
// Permit 2 Witness Order Type.
string internal constant PERMIT2_ORDER_TYPE =
string(
abi.encodePacked(
"Request witness)",
abi.encodePacked(BasicRequestLib.BASIC_REQUEST_TYPE, REQUEST_TYPE),
Permit2Lib.TOKEN_PERMISSIONS_TYPE
)
);
// REQUEST TYPE encode packed
bytes internal constant REQUEST_TYPE =
abi.encodePacked(
"Request(",
"BasicRequest basicReq,",
"address[] exclusiveTransmitters,",
"bytes32 metadata,",
"bytes affiliateFees,",
"uint256 minDestGas,",
"bytes destinationPayload)"
);
// SWAP EXEC TYPE.
// @review this lib again, make sure things are solid
bytes internal constant SWAP_EXEC_TYPE =
abi.encodePacked(
"SwapExec(",
"Request request,",
"uint256[] fulfilAmounts,",
"bytes swapPayload,",
"address swapRouter,",
"bytes userSignature,",
"address beneficiary)"
);
// BUNGEE_REQUEST_TYPE
bytes internal constant BUNGEE_REQUEST_TYPE = abi.encodePacked(REQUEST_TYPE, BasicRequestLib.BASIC_REQUEST_TYPE);
// Keccak Hash of BUNGEE_REQUEST_TYPE
bytes32 internal constant BUNGEE_REQUEST_TYPE_HASH = keccak256(BUNGEE_REQUEST_TYPE);
// Exec Type.
bytes internal constant EXEC_TYPE = abi.encodePacked(SWAP_EXEC_TYPE, REQUEST_TYPE);
// Keccak Hash of Exec Type.
bytes32 internal constant SWAP_EXEC_TYPE_HASH = keccak256(EXEC_TYPE);
/// @notice Hash of request on the swap chain
/// @param request request that is signe by the user
function hashRequest(Request memory request) internal view returns (bytes32) {
return
keccak256(
abi.encode(
BUNGEE_REQUEST_TYPE_HASH,
request.basicReq.hash(),
keccak256(abi.encodePacked(request.exclusiveTransmitters)),
request.metadata,
keccak256(request.affiliateFees),
request.minDestGas,
keccak256(request.destinationPayload)
)
);
}
/// @notice Hash of Swap Exec on the swap chain
/// @param execution Transmitter submitted swap exec object
function hashSwapExec(SwapExec memory execution) internal view returns (bytes32) {
return
keccak256(
abi.encode(
SWAP_EXEC_TYPE_HASH,
hashRequest(execution.request),
keccak256(abi.encodePacked(execution.fulfilAmounts)),
keccak256(execution.swapPayload),
execution.swapRouter,
keccak256(execution.userSignature),
execution.beneficiary
)
);
}
/// @notice hash a batch of swap execs
/// @param swapExecs batch of swap execs to be hashed
function hashBatch(SwapExec[] memory swapExecs) internal view returns (bytes32) {
unchecked {
bytes32 outputHash = keccak256("BUNGEE_SWAP_EXEC");
// Hash all of the swap execs present in the batch.
for (uint256 i = 0; i < swapExecs.length; i++) {
outputHash = keccak256(abi.encode(outputHash, hashSwapExec(swapExecs[i])));
}
return outputHash;
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.17;
import {OnlyOwner, OnlyNominee} from "../common/BungeeErrors.sol";
abstract contract Ownable {
address private _owner;
address private _nominee;
event OwnerNominated(address indexed nominee);
event OwnerClaimed(address indexed claimer);
constructor(address owner_) {
_claimOwner(owner_);
}
modifier onlyOwner() {
if (msg.sender != _owner) {
revert OnlyOwner();
}
_;
}
function owner() public view returns (address) {
return _owner;
}
function nominee() public view returns (address) {
return _nominee;
}
function nominateOwner(address nominee_) external {
if (msg.sender != _owner) {
revert OnlyOwner();
}
_nominee = nominee_;
emit OwnerNominated(_nominee);
}
function claimOwner() external {
if (msg.sender != _nominee) {
revert OnlyNominee();
}
_claimOwner(msg.sender);
}
function _claimOwner(address claimer_) internal {
_owner = claimer_;
_nominee = address(0);
emit OwnerClaimed(claimer_);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidMsg","type":"error"},{"inputs":[],"name":"InvalidMultipleNativeTokens","type":"error"},{"inputs":[],"name":"InvalidStake","type":"error"},{"inputs":[],"name":"MinOutputNotMet","type":"error"},{"inputs":[],"name":"MofaSignatureInvalid","type":"error"},{"inputs":[],"name":"OnlyNominee","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"RouterAlreadyRegistered","type":"error"},{"inputs":[],"name":"RouterAlreadyWhitelisted","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WrongAffiliateFeeLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimer","type":"address"}],"name":"OwnerClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nominee","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestHash","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"implId","type":"uint8"},{"indexed":false,"internalType":"address","name":"transmitter","type":"address"},{"indexed":false,"internalType":"bytes","name":"execution","type":"bytes"}],"name":"RequestExtracted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestHash","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"implId","type":"uint8"},{"indexed":false,"internalType":"address","name":"fulfiller","type":"address"},{"indexed":false,"internalType":"bytes","name":"execution","type":"bytes"}],"name":"RequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestHash","type":"bytes32"}],"name":"RequestSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32[]","name":"requestHashes","type":"bytes32[]"},{"indexed":false,"internalType":"uint8","name":"implId","type":"uint8"},{"indexed":false,"internalType":"address","name":"transmitter","type":"address"},{"indexed":false,"internalType":"uint256","name":"outboundFees","type":"uint256"}],"name":"RequestsSettledOnDestination","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawOnDestination","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawOnOrigin","type":"event"},{"inputs":[],"name":"CALLDATA_EXECUTOR","outputs":[{"internalType":"contract ICalldataExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXPIRY_BUFFER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_COLLECTOR","outputs":[{"internalType":"contract IFeeCollector","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MOFA_SIGNER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_TOKEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"contract ISignatureTransfer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SINGLE_OUTPUT_IMPL_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKE_VAULT","outputs":[{"internalType":"contract IStakeVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_EXECUTOR","outputs":[{"internalType":"contract ISwapExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_REQUEST_IMPL_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWITCHBOARD_ROUTER","outputs":[{"internalType":"contract ISwitchboardRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"beneficiarySettlements","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"checkCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"bungeeGateway","type":"address"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address[]","name":"outputTokens","type":"address[]"},{"internalType":"uint256[]","name":"minOutputAmounts","type":"uint256[]"}],"internalType":"struct BasicRequest","name":"basicReq","type":"tuple"},{"internalType":"address[]","name":"exclusiveTransmitters","type":"address[]"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"bytes","name":"affiliateFees","type":"bytes"},{"internalType":"uint256","name":"minDestGas","type":"uint256"},{"internalType":"bytes","name":"destinationPayload","type":"bytes"}],"internalType":"struct Request","name":"request","type":"tuple"},{"internalType":"uint256[]","name":"fulfilAmounts","type":"uint256[]"},{"internalType":"bytes","name":"swapPayload","type":"bytes"},{"internalType":"address","name":"swapRouter","type":"address"},{"internalType":"bytes","name":"userSignature","type":"bytes"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct SwapExec[]","name":"swapExecs","type":"tuple[]"},{"internalType":"bytes","name":"mofaSignature","type":"bytes"}],"name":"extractAndSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestHash","type":"bytes32"}],"name":"getSingleOutputExtractedRequest","outputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"uint32","name":"switchboardId","type":"uint32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"promisedAmount","type":"uint256"},{"internalType":"uint256","name":"promisedRefuelAmount","type":"uint256"},{"internalType":"bytes","name":"affiliateFees","type":"bytes"}],"internalType":"struct ExtractedRequest","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestHash","type":"bytes32"}],"name":"getSingleOutputFulfilledRequest","outputs":[{"components":[{"internalType":"uint256","name":"fulfilledAmount","type":"uint256"},{"internalType":"uint256","name":"fulfilledRefuelAmount","type":"uint256"},{"internalType":"bool","name":"processed","type":"bool"}],"internalType":"struct FulfilledRequest","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"name":"getWhitelistedReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"isBungeeRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"whitelisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nominee_","type":"address"}],"name":"nominateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominee","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"receiveMsg","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"stakedRouter","type":"address"}],"name":"registerStakedRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"capacity","type":"uint256"}],"name":"registerTransmitterStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"whitelistedRouter","type":"address"}],"name":"registerWhitelistedRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_calldataExecutor","type":"address"}],"name":"setCalldataExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_expiryBuffer","type":"uint256"}],"name":"setExpiryBuffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mofaSigner","type":"address"}],"name":"setMofaSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stakeVault","type":"address"}],"name":"setStakeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapExecutor","type":"address"}],"name":"setSwapExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_switchboardRouter","type":"address"}],"name":"setSwitchboardRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"address","name":"router","type":"address"}],"name":"setWhitelistedReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"transmitterCapacity","outputs":[{"internalType":"uint256","name":"capacity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"withdrawBeneficiarySettlement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"capacity","type":"uint256"}],"name":"withdrawTransmitterStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestHash","type":"bytes32"}],"name":"withdrawnRequests","outputs":[{"internalType":"bool","name":"withdrawn","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b5060405162003b2b38038062003b2b8339810160408190526200003491620000c9565b818181620000428162000059565b506001600160a01b03166080525062000101915050565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b80516001600160a01b0381168114620000c457600080fd5b919050565b60008060408385031215620000dd57600080fd5b620000e883620000ac565b9150620000f860208401620000ac565b90509250929050565b608051613a006200012b60003960008181610520015281816116f60152611d350152613a006000f3fe60806040526004361061023b5760003560e01c80637373161f1161012e578063a42dce80116100ab578063df2ebdbb1161006f578063df2ebdbb1461074c578063e1282c5c14610774578063e9899ed2146107b8578063f36ba4d8146107d8578063f8281486146107f857600080fd5b8063a42dce80146106d0578063ae3100c0146106f0578063b746078a14610706578063bd18826014610719578063cc6dc63a1461072c57600080fd5b806380f7013e116100f257806380f7013e14610625578063823d00881461065d5780638da5cb5b14610672578063967aef08146106905780639ed0cb13146106b057600080fd5b80637373161f1461056257806374f8d3fd1461058257806376479d1b146105c5578063795d86b8146105e55780637f660b011461060557600080fd5b80633af32abf116101bc5780635b94db27116101805780635b94db271461049e5780636a0706db146104be5780636a7372da146104de5780636afdd8501461050e578063733957f81461054257600080fd5b80633af32abf146103c75780633bd1adec146103f75780633cbc7eaa1461040c5780633de408a1146104335780634c7a77321461047157600080fd5b80631e789c36116102035780631e789c361461030b57806320798eb71461035457806320f99c0a1461036957806320ff430b1461038757806331feeadd146103a757600080fd5b80630b345879146102405780630c0a0ccb1461027d5780630cb352e0146102ab5780630e4bfd6e146102cb57806312f07c25146102eb575b600080fd5b34801561024c57600080fd5b50600454610260906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561028957600080fd5b5061029d6102983660046128a4565b610818565b604051908152602001610274565b3480156102b757600080fd5b50600554610260906001600160a01b031681565b3480156102d757600080fd5b50600354610260906001600160a01b031681565b3480156102f757600080fd5b50600254610260906001600160a01b031681565b34801561031757600080fd5b506103446103263660046128d7565b6001600160a01b03166000908152600c602052604090205460ff1690565b6040519015158152602001610274565b6103676103623660046128f9565b610845565b005b34801561037557600080fd5b506001546001600160a01b0316610260565b34801561039357600080fd5b506103676103a2366004612923565b610975565b3480156103b357600080fd5b506103676103c236600461295f565b6109ab565b3480156103d357600080fd5b506103446103e23660046128d7565b600d6020526000908152604090205460ff1681565b34801561040357600080fd5b50610367610a80565b34801561041857600080fd5b50610421600181565b60405160ff9091168152602001610274565b34801561043f57600080fd5b5061029d61044e36600461295f565b601060209081526000938452604080852082529284528284209052825290205481565b34801561047d57600080fd5b5061049161048c3660046129a2565b610ab6565b6040516102749190612a0b565b3480156104aa57600080fd5b506103676104b93660046128d7565b610c60565b3480156104ca57600080fd5b506103676104d93660046128d7565b610cd5565b3480156104ea57600080fd5b506103446104f93660046129a2565b600f6020526000908152604090205460ff1681565b34801561051a57600080fd5b506102607f000000000000000000000000000000000000000000000000000000000000000081565b34801561054e57600080fd5b5061036761055d3660046128d7565b610d22565b34801561056e57600080fd5b5061036761057d3660046129a2565b610d6f565b34801561058e57600080fd5b5061026061059d3660046128f9565b6001600160a01b039182166000908152600b6020908152604080832093835292905220541690565b3480156105d157600080fd5b506103676105e03660046128d7565b610d9f565b3480156105f157600080fd5b506103676106003660046128d7565b610e6d565b34801561061157600080fd5b50600654610260906001600160a01b031681565b34801561063157600080fd5b5061029d6106403660046128a4565b600e60209081526000928352604080842090915290825290205481565b34801561066957600080fd5b50610421600281565b34801561067e57600080fd5b506000546001600160a01b0316610260565b34801561069c57600080fd5b506103676106ab3660046128f9565b610edb565b3480156106bc57600080fd5b506103676106cb366004612af6565b610f9e565b3480156106dc57600080fd5b506103676106eb3660046128d7565b611006565b3480156106fc57600080fd5b5061029d60085481565b610367610714366004612b71565b611053565b610367610727366004612bb2565b61107e565b34801561073857600080fd5b506103676107473660046128d7565b61125a565b34801561075857600080fd5b5061026073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561078057600080fd5b5061079461078f3660046129a2565b6112a7565b60408051825181526020808401519082015291810151151590820152606001610274565b3480156107c457600080fd5b506103676107d33660046128d7565b61130b565b3480156107e457600080fd5b506103676107f33660046128d7565b611358565b34801561080457600080fd5b50600754610260906001600160a01b031681565b6001600160a01b038083166000908152600e60209081526040808320938516835292905220545b92915050565b336000908152600e602090815260408083206001600160a01b0386168452909152902054610874908290612c61565b336000908152600e602090815260408083206001600160a01b03871680855292529091209190915573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed1901610955578034146108d757604051634eba4d4960e11b815260040160405180910390fd5b6007546040516000916001600160a01b03169061138890849084818181858888f193505050503d8060008114610929576040519150601f19603f3d011682016040523d82523d6000602084013e61092e565b606091505b5050905080610950576040516312171d8360e31b815260040160405180910390fd5b505050565b600754610971906001600160a01b0384811691339116846113a5565b5050565b6000546001600160a01b031633146109a057604051635fc483c560e01b815260040160405180910390fd5b61095083828461143f565b6001600160a01b03808416600090815260106020908152604080832086851684528252808320938516835292905220548015610a7a576001600160a01b038481166000818152601060209081526040808320888616808552908352818420958816808552959092528083209290925590516362524dd760e01b81526004810193909352602483018490526044830191909152906362524dd790606401600060405180830381600087803b158015610a6157600080fd5b505af1158015610a75573d6000803e3d6000fd5b505050505b50505050565b6001546001600160a01b03163314610aab57604051637c91ccdd60e01b815260040160405180910390fd5b610ab4336114f1565b565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101919091526000828152600a60208181526040928390208351610180810185528154815260018201546001600160a01b0390811693820193909352600282015483169481019490945260038101548083166060860152600160a01b900463ffffffff1660808501526004810154821660a08501526005810154821660c0850152600681015490911660e0840152600781015461010084015260088101546101208401526009810154610140840152908101805461016084019190610bd790612c74565b80601f0160208091040260200160405190810160405280929190818152602001828054610c0390612c74565b8015610c505780601f10610c2557610100808354040283529160200191610c50565b820191906000526020600020905b815481529060010190602001808311610c3357829003601f168201915b5050505050815250509050919050565b6000546001600160a01b03163314610c8b57604051635fc483c560e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b6000546001600160a01b03163314610d0057604051635fc483c560e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610d4d57604051635fc483c560e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610d9a57604051635fc483c560e01b815260040160405180910390fd5b600855565b6000546001600160a01b03163314610dca57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600d602052604090205460ff1615610e045760405163406c5bd360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff1615610e3e57604051633ba24ff960e11b815260040160405180910390fd5b6001600160a01b0381166000908152600d60205260409020805460ff19166001179055610e6a81611544565b50565b6000546001600160a01b03163314610e9857604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff1615610ed257604051633ba24ff960e11b815260040160405180910390fd5b610e6a81611544565b336000908152600e602090815260408083206001600160a01b0386168452909152902054610f0a908290612cae565b336000818152600e602090815260408083206001600160a01b038881168086529190935292819020949094556007549351632385922d60e01b81526004810192909252602482018590526044820192909252911690632385922d90606401600060405180830381600087803b158015610f8257600080fd5b505af1158015610f96573d6000803e3d6000fd5b505050505050565b6000546001600160a01b03163314610fc957604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b039081166000908152600b60209081526040808320948352939052919091208054919092166001600160a01b0319909116179055565b6000546001600160a01b0316331461103157604051635fc483c560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b0316331461097157604051631bd147a760e01b815260040160405180910390fd5b6110bf848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061156892505050565b60005b838110156112535760008585838181106110de576110de612cc1565b90506020028101906110f09190612cd7565b6110f99061316d565b90506000805b8251516101000151518110156111e157825151610120015180518290811061112957611129612cc1565b60200260200101518360200151828151811061114757611147612cc1565b6020026020010151101561116e5760405163308657c360e21b815260040160405180910390fd5b8251516101000151805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee91908390811061119f5761119f612cc1565b60200260200101516001600160a01b0316036111d95781156111d457604051639d91bc6560e01b815260040160405180910390fd5b600191505b6001016110ff565b5060006111f183600001516115bb565b6040840151519091501561120e5761120981846116d4565b611218565b6112188184611d13565b825180516080808201519083015160208701516101009093015160a0909401516112489492939192908690611f81565b5050506001016110c2565b5050505050565b6000546001600160a01b0316331461128557604051635fc483c560e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6112cd604051806060016040528060008152602001600081526020016000151581525090565b506000908152600960209081526040918290208251606081018452815481526001820154928101929092526002015460ff1615159181019190915290565b6000546001600160a01b0316331461133657604051635fc483c560e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461138357604051635fc483c560e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806112535760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016114dd576000816001600160a01b03168361138890604051600060405180830381858888f193505050503d80600081146114b6576040519150601f19603f3d011682016040523d82523d6000602084013e6114bb565b606091505b5050905080610a7a576040516312171d8360e31b815260040160405180910390fd5b6109506001600160a01b0384168284612067565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b6001600160a01b03166000908152600c60205260409020805460ff19166001179055565b600061157c6115778486613179565b6120e8565b9050600061158a8284612174565b6002549091506001600160a01b0380831691161461125357604051633c6ae50160e11b815260040160405180910390fd5b60006040516020016115cc906131ec565b6040516020818303038152906040526040516020016115ea906132be565b60408051601f198184030181529082905261160892916020016133f7565b6040516020818303038152906040528051906020012061162b8360000151612194565b60208085015160405161163e9201613426565b60405160208183030381529060405280519060200120846040015185606001518051906020012086608001518760a00151805190602001206040516020016116b79796959493929190968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b604051602081830303815290604052805190602001209050919050565b80515160c081015160e082015160408301516020909301516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363137c29fe9361172b93909290919061229a565b83515160e00151600454604080518082018252600080825260209182015281518083019092526001600160a01b0390921681529081019190915284515160600151604051879061177d906020016132be565b60405160208183030381529060405260405160200161179b906131ec565b60408051601f19818403018152908290526117b992916020016133f7565b60408051601f1981840301815260608301909152602e80835290919061399d60208301396040516020016117ee929190613465565b60408051601f198184030181529082905260808901516001600160e01b031960e089901b16835261182596959493926004016134b3565b600060405180830381600087803b15801561183f57600080fd5b505af1158015611853573d6000803e3d6000fd5b50508251516101000151516000925090506001600160401b0381111561187b5761187b612cf7565b6040519080825280602002602001820160405280156118a4578160200160208202803683370190505b50905060005b825151610100015151811015611a02578251516101000151805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9190839081106118eb576118eb612cc1565b60200260200101516001600160a01b03160361193b57826000015160000151608001516001600160a01b03163182828151811061192a5761192a612cc1565b6020026020010181815250506119f0565b825151610100015180518290811061195557611955612cc1565b6020908102919091010151835151608001516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156119ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d19190613556565b8282815181106119e3576119e3612cc1565b6020026020010181815250505b806119fa8161356f565b9150506118aa565b508151805160e001516060909101516000918291611a2091906122fc565b9093509150508115611ab4576004805485515160c081015160e09091015160608801516040808a01516006549151631c30759960e11b81526001600160a01b0396871697633860eb3297611a7d9796959416918a918c9101613588565b600060405180830381600087803b158015611a9757600080fd5b505af1158015611aab573d6000803e3d6000fd5b50505050611b30565b6004805485515160c081015160e09091015160608801516040808a0151905163017c1d7560e31b81526001600160a01b0390951695630be0eba895611afd9594939291016135d6565b600060405180830381600087803b158015611b1757600080fd5b505af1158015611b2b573d6000803e3d6000fd5b505050505b60005b845151610100015151811015611cb1578451516101000151805160009173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9184908110611b7657611b76612cc1565b60200260200101516001600160a01b031603611ba35750845151608001516001600160a01b031631611c3c565b8551516101000151805183908110611bbd57611bbd612cc1565b6020908102919091010151865151608001516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015611c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c399190613556565b90505b85602001518281518110611c5257611c52612cc1565b6020026020010151858381518110611c6c57611c6c612cc1565b602002602001015182611c7f9190612cae565b1015611c9e5760405163308657c360e21b815260040160405180910390fd5b5080611ca98161356f565b915050611b33565b50847fd83e4fbd120e768f3bb813ecfa1a2b16c323fa7dfa07db1cd6434b3cbc97bc7560023387604051602001611ce89190613687565b60408051601f1981840301815290829052611d04939291613863565b60405180910390a25050505050565b80515160c081015160e082015160408301516020909301516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363137c29fe93611d6a93909290919061229a565b83515160e00151604080518082018252600080825260209182015281518083018352308152808201939093528651516060015191518891611dab91016132be565b604051602081830303815290604052604051602001611dc9906131ec565b60408051601f1981840301815290829052611de792916020016133f7565b60408051601f1981840301815260608301909152602e80835290919061399d6020830139604051602001611e1c929190613465565b60408051601f198184030181529082905260808901516001600160e01b031960e089901b168352611e5396959493926004016134b3565b600060405180830381600087803b158015611e6d57600080fd5b505af1158015611e81573d6000803e3d6000fd5b50508251805160e00151606090910151600093508392508291611ea3916122fc565b919450925090508115611ec25783515160c00151611ec2908383612399565b60005b846020015151811015611f325784515161010001518051611f2a919083908110611ef157611ef1612cc1565b60200260200101513387602001518481518110611f1057611f10612cc1565b602002602001015188600001516000015160800151612425565b600101611ec5565b5083515160c0015160a0850151611f4b9190859061143f565b847fd83e4fbd120e768f3bb813ecfa1a2b16c323fa7dfa07db1cd6434b3cbc97bc7560023387604051602001611ce89190613687565b80511580611f9657506001600160a01b038616155b80611fa957506001600160a01b03861630145b610f9657600084838584604051602401611fc69493929190613899565b60408051601f198184030181529181526020820180516001600160e01b0316636bf9b1d160e01b17905260055490516337a8727d60e11b81529192506001600160a01b031690636f50e4fa90612024908a9085908b906004016138e3565b6020604051808303816000875af1158015612043573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a759190613917565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610a7a5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611436565b60007fc746f6e6da790dff84d0c9f6e755a8d7633f3ee530ccaed5b82aa1d0ccec224f815b835181101561216d578161213985838151811061212c5761212c612cc1565b60200260200101516124de565b60408051602081019390935282015260600160408051601f198184030181529190528051602090910120915060010161210d565b5092915050565b60008061218084612698565b905061218c81846126d3565b949350505050565b60006040516020016121a5906132be565b604051602081830303815290604052805190602001204683602001518460400151856060015186608001518760a001518860c001518960e001518a61010001516040516020016121f59190613426565b604051602081830303815290604052805190602001208b61012001516040516020016122219190613939565b60408051601f1981840301815282825280516020918201209083019c909c52810199909952606089019790975260808801959095526001600160a01b0393841660a088015291831660c0870152821660e086015216610100840152610120830152610140820152610160810191909152610180016116b7565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a0810182526001600160a01b039590951660608601908152608086019490945292845260208401919091529082015290565b6000806000806000808651111561238e5760008651601a1461233157604051634115207f60e01b815260040160405180910390fd5b61233c876014612752565b90506123498760006127af565b925065ffffffffffff81161561238c57662386f26fc1000061237365ffffffffffff83168a613963565b61237d919061397a565b91506123898289612cae565b97505b505b959690945092505050565b6006546123b290849084906001600160a01b031661143f565b60065460405163404e3d4960e01b81526001600160a01b0383811660048301526024820185905285811660448301529091169063404e3d4990606401600060405180830381600087803b15801561240857600080fd5b505af115801561241c573d6000803e3d6000fd5b50505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016124c9576000816001600160a01b03168361138890604051600060405180830381858888f193505050503d806000811461249c576040519150601f19603f3d011682016040523d82523d6000602084013e6124a1565b606091505b50509050806124c3576040516312171d8360e31b815260040160405180910390fd5b50610a7a565b610a7a6001600160a01b0385168483856113a5565b604051680a6eec2e08af0cac6560bb1b60208201526f14995c5d595cdd081c995c5d595cdd0b60821b60298201527f75696e743235365b5d2066756c66696c416d6f756e74732c0000000000000000603982015271189e5d195cc81cddd85c14185e5b1bd8590b60721b6051820152721859191c995cdcc81cddd85c149bdd5d195c8b606a1b606382015273189e5d195cc81d5cd95c94da59db985d1d5c994b60621b607682015273616464726573732062656e65666963696172792960601b608a820152600090609e016040516020818303038152906040526040516020016125c7906131ec565b60408051601f19818403018152908290526125e592916020016133f7565b6040516020818303038152906040528051906020012061260883600001516115bb565b60208085015160405161261b9201613939565b60408051601f198184030181528282528051602091820120878301518051908301206060808a01516080808c015180519087012060a0808e0151978a019b909b529688019890985290860192909252948401949094526001600160a01b039384169483019490945260c0820152911660e0820152610100016116b7565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016116b7565b6000806000806126e285612814565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa15801561273d573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600061275f826006612c61565b835110156127a65760405162461bcd60e51b8152602060048201526014602482015273746f55696e7434385f6f75744f66426f756e647360601b6044820152606401611436565b50016006015190565b60006127bc826014612c61565b835110156128045760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401611436565b500160200151600160601b900490565b6000806000835160411461286a5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401611436565b50505060208101516040820151606090920151909260009190911a90565b80356001600160a01b038116811461289f57600080fd5b919050565b600080604083850312156128b757600080fd5b6128c083612888565b91506128ce60208401612888565b90509250929050565b6000602082840312156128e957600080fd5b6128f282612888565b9392505050565b6000806040838503121561290c57600080fd5b61291583612888565b946020939093013593505050565b60008060006060848603121561293857600080fd5b61294184612888565b925061294f60208501612888565b9150604084013590509250925092565b60008060006060848603121561297457600080fd5b61297d84612888565b925061298b60208501612888565b915061299960408501612888565b90509250925092565b6000602082840312156129b457600080fd5b5035919050565b60005b838110156129d65781810151838201526020016129be565b50506000910152565b600081518084526129f78160208601602086016129bb565b601f01601f19169290920160200192915050565b602081528151602082015260006020830151612a3260408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b038116608084015250608083015163ffffffff811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100612ab5818501836001600160a01b03169052565b84015161012084810191909152840151610140808501919091528401516101608085019190915284015161018080850152905061218c6101a08401826129df565b600080600060608486031215612b0b57600080fd5b612b1484612888565b92506020840135915061299960408501612888565b60008083601f840112612b3b57600080fd5b5081356001600160401b03811115612b5257600080fd5b602083019150836020828501011115612b6a57600080fd5b9250929050565b60008060208385031215612b8457600080fd5b82356001600160401b03811115612b9a57600080fd5b612ba685828601612b29565b90969095509350505050565b60008060008060408587031215612bc857600080fd5b84356001600160401b0380821115612bdf57600080fd5b818701915087601f830112612bf357600080fd5b813581811115612c0257600080fd5b8860208260051b8501011115612c1757600080fd5b602092830196509450908601359080821115612c3257600080fd5b50612c3f87828801612b29565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561083f5761083f612c4b565b600181811c90821680612c8857607f821691505b602082108103612ca857634e487b7160e01b600052602260045260246000fd5b50919050565b8181038181111561083f5761083f612c4b565b634e487b7160e01b600052603260045260246000fd5b6000823560be19833603018112612ced57600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715612d3057612d30612cf7565b60405290565b60405160c081016001600160401b0381118282101715612d3057612d30612cf7565b604051601f8201601f191681016001600160401b0381118282101715612d8057612d80612cf7565b604052919050565b60006001600160401b03821115612da157612da1612cf7565b5060051b60200190565b600082601f830112612dbc57600080fd5b81356020612dd1612dcc83612d88565b612d58565b82815260059290921b84018101918181019086841115612df057600080fd5b8286015b84811015612e1257612e0581612888565b8352918301918301612df4565b509695505050505050565b600082601f830112612e2e57600080fd5b81356020612e3e612dcc83612d88565b82815260059290921b84018101918181019086841115612e5d57600080fd5b8286015b84811015612e125780358352918301918301612e61565b60006101408284031215612e8b57600080fd5b612e93612d0d565b9050813581526020820135602082015260408201356040820152612eb960608301612888565b6060820152612eca60808301612888565b6080820152612edb60a08301612888565b60a0820152612eec60c08301612888565b60c082015260e082013560e0820152610100808301356001600160401b0380821115612f1757600080fd5b612f2386838701612dab565b83850152610120925082850135915080821115612f3f57600080fd5b50612f4c85828601612e1d565b82840152505092915050565b600082601f830112612f6957600080fd5b81356001600160401b03811115612f8257612f82612cf7565b612f95601f8201601f1916602001612d58565b818152846020838601011115612faa57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215612fd957600080fd5b612fe1612d36565b905081356001600160401b0380821115612ffa57600080fd5b61300685838601612e78565b8352602084013591508082111561301c57600080fd5b61302885838601612dab565b602084015260408401356040840152606084013591508082111561304b57600080fd5b61305785838601612f58565b60608401526080840135608084015260a084013591508082111561307a57600080fd5b5061308784828501612f58565b60a08301525092915050565b600060c082840312156130a557600080fd5b6130ad612d36565b905081356001600160401b03808211156130c657600080fd5b6130d285838601612fc7565b835260208401359150808211156130e857600080fd5b6130f485838601612e1d565b6020840152604084013591508082111561310d57600080fd5b61311985838601612f58565b604084015261312a60608501612888565b6060840152608084013591508082111561314357600080fd5b5061315084828501612f58565b60808301525061316260a08301612888565b60a082015292915050565b600061083f3683613093565b6000613187612dcc84612d88565b80848252602080830192508560051b8501368111156131a557600080fd5b855b818110156131e05780356001600160401b038111156131c65760008081fd5b6131d236828a01613093565b8652509382019382016131a7565b50919695505050505050565b670a4cae2eacae6e8560c31b81527510985cda58d4995c5d595cdd0818985cda58d4995c4b60521b60088201527f616464726573735b5d206578636c75736976655472616e736d6974746572732c601e82015270189e5d195ccccc881b595d1859185d184b607a1b603e82015273189e5d195cc81859999a5b1a585d195199595ccb60621b604f820152721d5a5b9d0c8d4d881b5a5b91195cdd11d85ccb606a1b60638201527f62797465732064657374696e6174696f6e5061796c6f616429000000000000006076820152608f0190565b6c084c2e6d2c6a4cae2eacae6e85609b1b81526f1d5a5b9d0c8d4d8818da185a5b92590b60821b600d820152701d5a5b9d0c8d4d88191958591b1a5b994b607a1b601d8201526d1d5a5b9d0c8d4d881b9bdb98d94b60921b602e8201526e1859191c995cdcc81cd95b99195c8b608a1b603c820152701859191c995cdcc81c9958d95a5d995c8b607a1b604b820152751859191c995cdcc8189d5b99d95951d85d195dd85e4b60521b605c820152721859191c995cdcc81a5b9c1d5d151bdad95b8b606a1b6072820152731d5a5b9d0c8d4d881a5b9c1d5d105b5bdd5b9d0b60621b60858201527f616464726573735b5d206f7574707574546f6b656e732c00000000000000000060998201527f75696e743235365b5d206d696e4f7574707574416d6f756e747329000000000060b082015260cb0190565b600083516134098184602088016129bb565b83519083019061341d8183602088016129bb565b01949350505050565b815160009082906020808601845b838110156134595781516001600160a01b031685529382019390820190600101613434565b50929695505050505050565b6f52657175657374207769746e6573732960801b8152600083516134908160108501602088016129bb565b8351908301906134a78160108401602088016129bb565b01601001949350505050565b60006101406134d6838a5180516001600160a01b03168252602090810151910152565b602089015160408401526040890151606084015261350a608084018980516001600160a01b03168252602090810151910152565b6001600160a01b03871660c084015260e083018690526101008301819052613534818401866129df565b905082810361012084015261354981856129df565b9998505050505050505050565b60006020828403121561356857600080fd5b5051919050565b60006001820161358157613581612c4b565b5060010190565b600060018060a01b03808a168352886020840152808816604084015260e060608401526135b860e08401886129df565b95811660808401529390931660a082015260c0015250949350505050565b6001600160a01b0385811682526020820185905283166040820152608060608201819052600090613609908301846129df565b9695505050505050565b600081518084526020808501945080840160005b8381101561364c5781516001600160a01b031687529582019590820190600101613627565b509495945050505050565b600081518084526020808501945080840160005b8381101561364c5781518752958201959082019060010161366b565b602081526000825160c06020840152805160c060e085015280516101a085015260208101516101c085015260408101516101e085015260608101516136d86102008601826001600160a01b03169052565b5060808101516001600160a01b0390811661022086015260a0820151811661024086015260c08201511661026085015260e0810151610280850152610100808201516101406102a087018190526137336102e0880183613613565b6101209485015188820361019f19016102c08a0152949092506137568386613657565b94506020860151925060df198089870301858a01526137758685613613565b95506040870151828a0152606087015194508089870301838a015261379a86866129df565b955060808701516101608a015260a0870151965080898703016101808a015250505050506137c881836129df565b9150506020840151601f19808584030160408601526137e78383613657565b9250604086015191508085840301606086015261380483836129df565b92506060860151915061382260808601836001600160a01b03169052565b60808601519150808584030160a08601525061383e82826129df565b91505060a084015161385b60c08501826001600160a01b03169052565b509392505050565b60ff841681526001600160a01b0383166020820152606060408201819052600090613890908301846129df565b95945050505050565b6080815260006138ac6080830187613657565b85602084015282810360408401526138c48186613613565b905082810360608401526138d881856129df565b979650505050505050565b6001600160a01b0384168152606060208201819052600090613907908301856129df565b9050826040830152949350505050565b60006020828403121561392957600080fd5b815180151581146128f257600080fd5b815160009082906020808601845b8381101561345957815185529382019390820190600101613947565b808202811582820484141761083f5761083f612c4b565b60008261399757634e487b7160e01b600052601260045260246000fd5b50049056fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a264697066735822122010064de8b9b5252036d9c43f9c5e86d4116a7ec01ed8342f3fc114035ee58f6664736f6c63430008130033000000000000000000000000daee4d2156de6fe6f7d50ca047136d758f96a6f0000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Deployed Bytecode
0x60806040526004361061023b5760003560e01c80637373161f1161012e578063a42dce80116100ab578063df2ebdbb1161006f578063df2ebdbb1461074c578063e1282c5c14610774578063e9899ed2146107b8578063f36ba4d8146107d8578063f8281486146107f857600080fd5b8063a42dce80146106d0578063ae3100c0146106f0578063b746078a14610706578063bd18826014610719578063cc6dc63a1461072c57600080fd5b806380f7013e116100f257806380f7013e14610625578063823d00881461065d5780638da5cb5b14610672578063967aef08146106905780639ed0cb13146106b057600080fd5b80637373161f1461056257806374f8d3fd1461058257806376479d1b146105c5578063795d86b8146105e55780637f660b011461060557600080fd5b80633af32abf116101bc5780635b94db27116101805780635b94db271461049e5780636a0706db146104be5780636a7372da146104de5780636afdd8501461050e578063733957f81461054257600080fd5b80633af32abf146103c75780633bd1adec146103f75780633cbc7eaa1461040c5780633de408a1146104335780634c7a77321461047157600080fd5b80631e789c36116102035780631e789c361461030b57806320798eb71461035457806320f99c0a1461036957806320ff430b1461038757806331feeadd146103a757600080fd5b80630b345879146102405780630c0a0ccb1461027d5780630cb352e0146102ab5780630e4bfd6e146102cb57806312f07c25146102eb575b600080fd5b34801561024c57600080fd5b50600454610260906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561028957600080fd5b5061029d6102983660046128a4565b610818565b604051908152602001610274565b3480156102b757600080fd5b50600554610260906001600160a01b031681565b3480156102d757600080fd5b50600354610260906001600160a01b031681565b3480156102f757600080fd5b50600254610260906001600160a01b031681565b34801561031757600080fd5b506103446103263660046128d7565b6001600160a01b03166000908152600c602052604090205460ff1690565b6040519015158152602001610274565b6103676103623660046128f9565b610845565b005b34801561037557600080fd5b506001546001600160a01b0316610260565b34801561039357600080fd5b506103676103a2366004612923565b610975565b3480156103b357600080fd5b506103676103c236600461295f565b6109ab565b3480156103d357600080fd5b506103446103e23660046128d7565b600d6020526000908152604090205460ff1681565b34801561040357600080fd5b50610367610a80565b34801561041857600080fd5b50610421600181565b60405160ff9091168152602001610274565b34801561043f57600080fd5b5061029d61044e36600461295f565b601060209081526000938452604080852082529284528284209052825290205481565b34801561047d57600080fd5b5061049161048c3660046129a2565b610ab6565b6040516102749190612a0b565b3480156104aa57600080fd5b506103676104b93660046128d7565b610c60565b3480156104ca57600080fd5b506103676104d93660046128d7565b610cd5565b3480156104ea57600080fd5b506103446104f93660046129a2565b600f6020526000908152604090205460ff1681565b34801561051a57600080fd5b506102607f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b34801561054e57600080fd5b5061036761055d3660046128d7565b610d22565b34801561056e57600080fd5b5061036761057d3660046129a2565b610d6f565b34801561058e57600080fd5b5061026061059d3660046128f9565b6001600160a01b039182166000908152600b6020908152604080832093835292905220541690565b3480156105d157600080fd5b506103676105e03660046128d7565b610d9f565b3480156105f157600080fd5b506103676106003660046128d7565b610e6d565b34801561061157600080fd5b50600654610260906001600160a01b031681565b34801561063157600080fd5b5061029d6106403660046128a4565b600e60209081526000928352604080842090915290825290205481565b34801561066957600080fd5b50610421600281565b34801561067e57600080fd5b506000546001600160a01b0316610260565b34801561069c57600080fd5b506103676106ab3660046128f9565b610edb565b3480156106bc57600080fd5b506103676106cb366004612af6565b610f9e565b3480156106dc57600080fd5b506103676106eb3660046128d7565b611006565b3480156106fc57600080fd5b5061029d60085481565b610367610714366004612b71565b611053565b610367610727366004612bb2565b61107e565b34801561073857600080fd5b506103676107473660046128d7565b61125a565b34801561075857600080fd5b5061026073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561078057600080fd5b5061079461078f3660046129a2565b6112a7565b60408051825181526020808401519082015291810151151590820152606001610274565b3480156107c457600080fd5b506103676107d33660046128d7565b61130b565b3480156107e457600080fd5b506103676107f33660046128d7565b611358565b34801561080457600080fd5b50600754610260906001600160a01b031681565b6001600160a01b038083166000908152600e60209081526040808320938516835292905220545b92915050565b336000908152600e602090815260408083206001600160a01b0386168452909152902054610874908290612c61565b336000908152600e602090815260408083206001600160a01b03871680855292529091209190915573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed1901610955578034146108d757604051634eba4d4960e11b815260040160405180910390fd5b6007546040516000916001600160a01b03169061138890849084818181858888f193505050503d8060008114610929576040519150601f19603f3d011682016040523d82523d6000602084013e61092e565b606091505b5050905080610950576040516312171d8360e31b815260040160405180910390fd5b505050565b600754610971906001600160a01b0384811691339116846113a5565b5050565b6000546001600160a01b031633146109a057604051635fc483c560e01b815260040160405180910390fd5b61095083828461143f565b6001600160a01b03808416600090815260106020908152604080832086851684528252808320938516835292905220548015610a7a576001600160a01b038481166000818152601060209081526040808320888616808552908352818420958816808552959092528083209290925590516362524dd760e01b81526004810193909352602483018490526044830191909152906362524dd790606401600060405180830381600087803b158015610a6157600080fd5b505af1158015610a75573d6000803e3d6000fd5b505050505b50505050565b6001546001600160a01b03163314610aab57604051637c91ccdd60e01b815260040160405180910390fd5b610ab4336114f1565b565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101919091526000828152600a60208181526040928390208351610180810185528154815260018201546001600160a01b0390811693820193909352600282015483169481019490945260038101548083166060860152600160a01b900463ffffffff1660808501526004810154821660a08501526005810154821660c0850152600681015490911660e0840152600781015461010084015260088101546101208401526009810154610140840152908101805461016084019190610bd790612c74565b80601f0160208091040260200160405190810160405280929190818152602001828054610c0390612c74565b8015610c505780601f10610c2557610100808354040283529160200191610c50565b820191906000526020600020905b815481529060010190602001808311610c3357829003601f168201915b5050505050815250509050919050565b6000546001600160a01b03163314610c8b57604051635fc483c560e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b6000546001600160a01b03163314610d0057604051635fc483c560e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610d4d57604051635fc483c560e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610d9a57604051635fc483c560e01b815260040160405180910390fd5b600855565b6000546001600160a01b03163314610dca57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600d602052604090205460ff1615610e045760405163406c5bd360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff1615610e3e57604051633ba24ff960e11b815260040160405180910390fd5b6001600160a01b0381166000908152600d60205260409020805460ff19166001179055610e6a81611544565b50565b6000546001600160a01b03163314610e9857604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff1615610ed257604051633ba24ff960e11b815260040160405180910390fd5b610e6a81611544565b336000908152600e602090815260408083206001600160a01b0386168452909152902054610f0a908290612cae565b336000818152600e602090815260408083206001600160a01b038881168086529190935292819020949094556007549351632385922d60e01b81526004810192909252602482018590526044820192909252911690632385922d90606401600060405180830381600087803b158015610f8257600080fd5b505af1158015610f96573d6000803e3d6000fd5b505050505050565b6000546001600160a01b03163314610fc957604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b039081166000908152600b60209081526040808320948352939052919091208054919092166001600160a01b0319909116179055565b6000546001600160a01b0316331461103157604051635fc483c560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b0316331461097157604051631bd147a760e01b815260040160405180910390fd5b6110bf848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061156892505050565b60005b838110156112535760008585838181106110de576110de612cc1565b90506020028101906110f09190612cd7565b6110f99061316d565b90506000805b8251516101000151518110156111e157825151610120015180518290811061112957611129612cc1565b60200260200101518360200151828151811061114757611147612cc1565b6020026020010151101561116e5760405163308657c360e21b815260040160405180910390fd5b8251516101000151805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee91908390811061119f5761119f612cc1565b60200260200101516001600160a01b0316036111d95781156111d457604051639d91bc6560e01b815260040160405180910390fd5b600191505b6001016110ff565b5060006111f183600001516115bb565b6040840151519091501561120e5761120981846116d4565b611218565b6112188184611d13565b825180516080808201519083015160208701516101009093015160a0909401516112489492939192908690611f81565b5050506001016110c2565b5050505050565b6000546001600160a01b0316331461128557604051635fc483c560e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6112cd604051806060016040528060008152602001600081526020016000151581525090565b506000908152600960209081526040918290208251606081018452815481526001820154928101929092526002015460ff1615159181019190915290565b6000546001600160a01b0316331461133657604051635fc483c560e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461138357604051635fc483c560e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806112535760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016114dd576000816001600160a01b03168361138890604051600060405180830381858888f193505050503d80600081146114b6576040519150601f19603f3d011682016040523d82523d6000602084013e6114bb565b606091505b5050905080610a7a576040516312171d8360e31b815260040160405180910390fd5b6109506001600160a01b0384168284612067565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b6001600160a01b03166000908152600c60205260409020805460ff19166001179055565b600061157c6115778486613179565b6120e8565b9050600061158a8284612174565b6002549091506001600160a01b0380831691161461125357604051633c6ae50160e11b815260040160405180910390fd5b60006040516020016115cc906131ec565b6040516020818303038152906040526040516020016115ea906132be565b60408051601f198184030181529082905261160892916020016133f7565b6040516020818303038152906040528051906020012061162b8360000151612194565b60208085015160405161163e9201613426565b60405160208183030381529060405280519060200120846040015185606001518051906020012086608001518760a00151805190602001206040516020016116b79796959493929190968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b604051602081830303815290604052805190602001209050919050565b80515160c081015160e082015160408301516020909301516001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3169363137c29fe9361172b93909290919061229a565b83515160e00151600454604080518082018252600080825260209182015281518083019092526001600160a01b0390921681529081019190915284515160600151604051879061177d906020016132be565b60405160208183030381529060405260405160200161179b906131ec565b60408051601f19818403018152908290526117b992916020016133f7565b60408051601f1981840301815260608301909152602e80835290919061399d60208301396040516020016117ee929190613465565b60408051601f198184030181529082905260808901516001600160e01b031960e089901b16835261182596959493926004016134b3565b600060405180830381600087803b15801561183f57600080fd5b505af1158015611853573d6000803e3d6000fd5b50508251516101000151516000925090506001600160401b0381111561187b5761187b612cf7565b6040519080825280602002602001820160405280156118a4578160200160208202803683370190505b50905060005b825151610100015151811015611a02578251516101000151805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9190839081106118eb576118eb612cc1565b60200260200101516001600160a01b03160361193b57826000015160000151608001516001600160a01b03163182828151811061192a5761192a612cc1565b6020026020010181815250506119f0565b825151610100015180518290811061195557611955612cc1565b6020908102919091010151835151608001516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156119ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d19190613556565b8282815181106119e3576119e3612cc1565b6020026020010181815250505b806119fa8161356f565b9150506118aa565b508151805160e001516060909101516000918291611a2091906122fc565b9093509150508115611ab4576004805485515160c081015160e09091015160608801516040808a01516006549151631c30759960e11b81526001600160a01b0396871697633860eb3297611a7d9796959416918a918c9101613588565b600060405180830381600087803b158015611a9757600080fd5b505af1158015611aab573d6000803e3d6000fd5b50505050611b30565b6004805485515160c081015160e09091015160608801516040808a0151905163017c1d7560e31b81526001600160a01b0390951695630be0eba895611afd9594939291016135d6565b600060405180830381600087803b158015611b1757600080fd5b505af1158015611b2b573d6000803e3d6000fd5b505050505b60005b845151610100015151811015611cb1578451516101000151805160009173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9184908110611b7657611b76612cc1565b60200260200101516001600160a01b031603611ba35750845151608001516001600160a01b031631611c3c565b8551516101000151805183908110611bbd57611bbd612cc1565b6020908102919091010151865151608001516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015611c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c399190613556565b90505b85602001518281518110611c5257611c52612cc1565b6020026020010151858381518110611c6c57611c6c612cc1565b602002602001015182611c7f9190612cae565b1015611c9e5760405163308657c360e21b815260040160405180910390fd5b5080611ca98161356f565b915050611b33565b50847fd83e4fbd120e768f3bb813ecfa1a2b16c323fa7dfa07db1cd6434b3cbc97bc7560023387604051602001611ce89190613687565b60408051601f1981840301815290829052611d04939291613863565b60405180910390a25050505050565b80515160c081015160e082015160408301516020909301516001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3169363137c29fe93611d6a93909290919061229a565b83515160e00151604080518082018252600080825260209182015281518083018352308152808201939093528651516060015191518891611dab91016132be565b604051602081830303815290604052604051602001611dc9906131ec565b60408051601f1981840301815290829052611de792916020016133f7565b60408051601f1981840301815260608301909152602e80835290919061399d6020830139604051602001611e1c929190613465565b60408051601f198184030181529082905260808901516001600160e01b031960e089901b168352611e5396959493926004016134b3565b600060405180830381600087803b158015611e6d57600080fd5b505af1158015611e81573d6000803e3d6000fd5b50508251805160e00151606090910151600093508392508291611ea3916122fc565b919450925090508115611ec25783515160c00151611ec2908383612399565b60005b846020015151811015611f325784515161010001518051611f2a919083908110611ef157611ef1612cc1565b60200260200101513387602001518481518110611f1057611f10612cc1565b602002602001015188600001516000015160800151612425565b600101611ec5565b5083515160c0015160a0850151611f4b9190859061143f565b847fd83e4fbd120e768f3bb813ecfa1a2b16c323fa7dfa07db1cd6434b3cbc97bc7560023387604051602001611ce89190613687565b80511580611f9657506001600160a01b038616155b80611fa957506001600160a01b03861630145b610f9657600084838584604051602401611fc69493929190613899565b60408051601f198184030181529181526020820180516001600160e01b0316636bf9b1d160e01b17905260055490516337a8727d60e11b81529192506001600160a01b031690636f50e4fa90612024908a9085908b906004016138e3565b6020604051808303816000875af1158015612043573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a759190613917565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610a7a5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611436565b60007fc746f6e6da790dff84d0c9f6e755a8d7633f3ee530ccaed5b82aa1d0ccec224f815b835181101561216d578161213985838151811061212c5761212c612cc1565b60200260200101516124de565b60408051602081019390935282015260600160408051601f198184030181529190528051602090910120915060010161210d565b5092915050565b60008061218084612698565b905061218c81846126d3565b949350505050565b60006040516020016121a5906132be565b604051602081830303815290604052805190602001204683602001518460400151856060015186608001518760a001518860c001518960e001518a61010001516040516020016121f59190613426565b604051602081830303815290604052805190602001208b61012001516040516020016122219190613939565b60408051601f1981840301815282825280516020918201209083019c909c52810199909952606089019790975260808801959095526001600160a01b0393841660a088015291831660c0870152821660e086015216610100840152610120830152610140820152610160810191909152610180016116b7565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a0810182526001600160a01b039590951660608601908152608086019490945292845260208401919091529082015290565b6000806000806000808651111561238e5760008651601a1461233157604051634115207f60e01b815260040160405180910390fd5b61233c876014612752565b90506123498760006127af565b925065ffffffffffff81161561238c57662386f26fc1000061237365ffffffffffff83168a613963565b61237d919061397a565b91506123898289612cae565b97505b505b959690945092505050565b6006546123b290849084906001600160a01b031661143f565b60065460405163404e3d4960e01b81526001600160a01b0383811660048301526024820185905285811660448301529091169063404e3d4990606401600060405180830381600087803b15801561240857600080fd5b505af115801561241c573d6000803e3d6000fd5b50505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016124c9576000816001600160a01b03168361138890604051600060405180830381858888f193505050503d806000811461249c576040519150601f19603f3d011682016040523d82523d6000602084013e6124a1565b606091505b50509050806124c3576040516312171d8360e31b815260040160405180910390fd5b50610a7a565b610a7a6001600160a01b0385168483856113a5565b604051680a6eec2e08af0cac6560bb1b60208201526f14995c5d595cdd081c995c5d595cdd0b60821b60298201527f75696e743235365b5d2066756c66696c416d6f756e74732c0000000000000000603982015271189e5d195cc81cddd85c14185e5b1bd8590b60721b6051820152721859191c995cdcc81cddd85c149bdd5d195c8b606a1b606382015273189e5d195cc81d5cd95c94da59db985d1d5c994b60621b607682015273616464726573732062656e65666963696172792960601b608a820152600090609e016040516020818303038152906040526040516020016125c7906131ec565b60408051601f19818403018152908290526125e592916020016133f7565b6040516020818303038152906040528051906020012061260883600001516115bb565b60208085015160405161261b9201613939565b60408051601f198184030181528282528051602091820120878301518051908301206060808a01516080808c015180519087012060a0808e0151978a019b909b529688019890985290860192909252948401949094526001600160a01b039384169483019490945260c0820152911660e0820152610100016116b7565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016116b7565b6000806000806126e285612814565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa15801561273d573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600061275f826006612c61565b835110156127a65760405162461bcd60e51b8152602060048201526014602482015273746f55696e7434385f6f75744f66426f756e647360601b6044820152606401611436565b50016006015190565b60006127bc826014612c61565b835110156128045760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401611436565b500160200151600160601b900490565b6000806000835160411461286a5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401611436565b50505060208101516040820151606090920151909260009190911a90565b80356001600160a01b038116811461289f57600080fd5b919050565b600080604083850312156128b757600080fd5b6128c083612888565b91506128ce60208401612888565b90509250929050565b6000602082840312156128e957600080fd5b6128f282612888565b9392505050565b6000806040838503121561290c57600080fd5b61291583612888565b946020939093013593505050565b60008060006060848603121561293857600080fd5b61294184612888565b925061294f60208501612888565b9150604084013590509250925092565b60008060006060848603121561297457600080fd5b61297d84612888565b925061298b60208501612888565b915061299960408501612888565b90509250925092565b6000602082840312156129b457600080fd5b5035919050565b60005b838110156129d65781810151838201526020016129be565b50506000910152565b600081518084526129f78160208601602086016129bb565b601f01601f19169290920160200192915050565b602081528151602082015260006020830151612a3260408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b038116608084015250608083015163ffffffff811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100612ab5818501836001600160a01b03169052565b84015161012084810191909152840151610140808501919091528401516101608085019190915284015161018080850152905061218c6101a08401826129df565b600080600060608486031215612b0b57600080fd5b612b1484612888565b92506020840135915061299960408501612888565b60008083601f840112612b3b57600080fd5b5081356001600160401b03811115612b5257600080fd5b602083019150836020828501011115612b6a57600080fd5b9250929050565b60008060208385031215612b8457600080fd5b82356001600160401b03811115612b9a57600080fd5b612ba685828601612b29565b90969095509350505050565b60008060008060408587031215612bc857600080fd5b84356001600160401b0380821115612bdf57600080fd5b818701915087601f830112612bf357600080fd5b813581811115612c0257600080fd5b8860208260051b8501011115612c1757600080fd5b602092830196509450908601359080821115612c3257600080fd5b50612c3f87828801612b29565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561083f5761083f612c4b565b600181811c90821680612c8857607f821691505b602082108103612ca857634e487b7160e01b600052602260045260246000fd5b50919050565b8181038181111561083f5761083f612c4b565b634e487b7160e01b600052603260045260246000fd5b6000823560be19833603018112612ced57600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715612d3057612d30612cf7565b60405290565b60405160c081016001600160401b0381118282101715612d3057612d30612cf7565b604051601f8201601f191681016001600160401b0381118282101715612d8057612d80612cf7565b604052919050565b60006001600160401b03821115612da157612da1612cf7565b5060051b60200190565b600082601f830112612dbc57600080fd5b81356020612dd1612dcc83612d88565b612d58565b82815260059290921b84018101918181019086841115612df057600080fd5b8286015b84811015612e1257612e0581612888565b8352918301918301612df4565b509695505050505050565b600082601f830112612e2e57600080fd5b81356020612e3e612dcc83612d88565b82815260059290921b84018101918181019086841115612e5d57600080fd5b8286015b84811015612e125780358352918301918301612e61565b60006101408284031215612e8b57600080fd5b612e93612d0d565b9050813581526020820135602082015260408201356040820152612eb960608301612888565b6060820152612eca60808301612888565b6080820152612edb60a08301612888565b60a0820152612eec60c08301612888565b60c082015260e082013560e0820152610100808301356001600160401b0380821115612f1757600080fd5b612f2386838701612dab565b83850152610120925082850135915080821115612f3f57600080fd5b50612f4c85828601612e1d565b82840152505092915050565b600082601f830112612f6957600080fd5b81356001600160401b03811115612f8257612f82612cf7565b612f95601f8201601f1916602001612d58565b818152846020838601011115612faa57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215612fd957600080fd5b612fe1612d36565b905081356001600160401b0380821115612ffa57600080fd5b61300685838601612e78565b8352602084013591508082111561301c57600080fd5b61302885838601612dab565b602084015260408401356040840152606084013591508082111561304b57600080fd5b61305785838601612f58565b60608401526080840135608084015260a084013591508082111561307a57600080fd5b5061308784828501612f58565b60a08301525092915050565b600060c082840312156130a557600080fd5b6130ad612d36565b905081356001600160401b03808211156130c657600080fd5b6130d285838601612fc7565b835260208401359150808211156130e857600080fd5b6130f485838601612e1d565b6020840152604084013591508082111561310d57600080fd5b61311985838601612f58565b604084015261312a60608501612888565b6060840152608084013591508082111561314357600080fd5b5061315084828501612f58565b60808301525061316260a08301612888565b60a082015292915050565b600061083f3683613093565b6000613187612dcc84612d88565b80848252602080830192508560051b8501368111156131a557600080fd5b855b818110156131e05780356001600160401b038111156131c65760008081fd5b6131d236828a01613093565b8652509382019382016131a7565b50919695505050505050565b670a4cae2eacae6e8560c31b81527510985cda58d4995c5d595cdd0818985cda58d4995c4b60521b60088201527f616464726573735b5d206578636c75736976655472616e736d6974746572732c601e82015270189e5d195ccccc881b595d1859185d184b607a1b603e82015273189e5d195cc81859999a5b1a585d195199595ccb60621b604f820152721d5a5b9d0c8d4d881b5a5b91195cdd11d85ccb606a1b60638201527f62797465732064657374696e6174696f6e5061796c6f616429000000000000006076820152608f0190565b6c084c2e6d2c6a4cae2eacae6e85609b1b81526f1d5a5b9d0c8d4d8818da185a5b92590b60821b600d820152701d5a5b9d0c8d4d88191958591b1a5b994b607a1b601d8201526d1d5a5b9d0c8d4d881b9bdb98d94b60921b602e8201526e1859191c995cdcc81cd95b99195c8b608a1b603c820152701859191c995cdcc81c9958d95a5d995c8b607a1b604b820152751859191c995cdcc8189d5b99d95951d85d195dd85e4b60521b605c820152721859191c995cdcc81a5b9c1d5d151bdad95b8b606a1b6072820152731d5a5b9d0c8d4d881a5b9c1d5d105b5bdd5b9d0b60621b60858201527f616464726573735b5d206f7574707574546f6b656e732c00000000000000000060998201527f75696e743235365b5d206d696e4f7574707574416d6f756e747329000000000060b082015260cb0190565b600083516134098184602088016129bb565b83519083019061341d8183602088016129bb565b01949350505050565b815160009082906020808601845b838110156134595781516001600160a01b031685529382019390820190600101613434565b50929695505050505050565b6f52657175657374207769746e6573732960801b8152600083516134908160108501602088016129bb565b8351908301906134a78160108401602088016129bb565b01601001949350505050565b60006101406134d6838a5180516001600160a01b03168252602090810151910152565b602089015160408401526040890151606084015261350a608084018980516001600160a01b03168252602090810151910152565b6001600160a01b03871660c084015260e083018690526101008301819052613534818401866129df565b905082810361012084015261354981856129df565b9998505050505050505050565b60006020828403121561356857600080fd5b5051919050565b60006001820161358157613581612c4b565b5060010190565b600060018060a01b03808a168352886020840152808816604084015260e060608401526135b860e08401886129df565b95811660808401529390931660a082015260c0015250949350505050565b6001600160a01b0385811682526020820185905283166040820152608060608201819052600090613609908301846129df565b9695505050505050565b600081518084526020808501945080840160005b8381101561364c5781516001600160a01b031687529582019590820190600101613627565b509495945050505050565b600081518084526020808501945080840160005b8381101561364c5781518752958201959082019060010161366b565b602081526000825160c06020840152805160c060e085015280516101a085015260208101516101c085015260408101516101e085015260608101516136d86102008601826001600160a01b03169052565b5060808101516001600160a01b0390811661022086015260a0820151811661024086015260c08201511661026085015260e0810151610280850152610100808201516101406102a087018190526137336102e0880183613613565b6101209485015188820361019f19016102c08a0152949092506137568386613657565b94506020860151925060df198089870301858a01526137758685613613565b95506040870151828a0152606087015194508089870301838a015261379a86866129df565b955060808701516101608a015260a0870151965080898703016101808a015250505050506137c881836129df565b9150506020840151601f19808584030160408601526137e78383613657565b9250604086015191508085840301606086015261380483836129df565b92506060860151915061382260808601836001600160a01b03169052565b60808601519150808584030160a08601525061383e82826129df565b91505060a084015161385b60c08501826001600160a01b03169052565b509392505050565b60ff841681526001600160a01b0383166020820152606060408201819052600090613890908301846129df565b95945050505050565b6080815260006138ac6080830187613657565b85602084015282810360408401526138c48186613613565b905082810360608401526138d881856129df565b979650505050505050565b6001600160a01b0384168152606060208201819052600090613907908301856129df565b9050826040830152949350505050565b60006020828403121561392957600080fd5b815180151581146128f257600080fd5b815160009082906020808601845b8381101561345957815185529382019390820190600101613947565b808202811582820484141761083f5761083f612c4b565b60008261399757634e487b7160e01b600052601260045260246000fd5b50049056fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a264697066735822122010064de8b9b5252036d9c43f9c5e86d4116a7ec01ed8342f3fc114035ee58f6664736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000daee4d2156de6fe6f7d50ca047136d758f96a6f0000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
-----Decoded View---------------
Arg [0] : _owner (address): 0xDaeE4D2156DE6fe6f7D50cA047136D758f96A6f0
Arg [1] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000daee4d2156de6fe6f7d50ca047136d758f96a6f0
Arg [1] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.04
Net Worth in ETH
Token Allocations
POL
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| POL | 100.00% | $0.116511 | 0.3521 | $0.041029 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.