Overview
S Balance
0 S
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
SingleOutputRequestImpl
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 {IBaseRouterSingleOutput as IBaseRouter} from "../interfaces/IBaseRouterSingleOutput.sol"; import {AuthenticationLib} from "../lib/AuthenticationLib.sol"; import {AffiliateFeesLib} from "../lib/AffiliateFeesLib.sol"; import { InsufficientNativeAmount, MofaSignatureInvalid, RouterNotRegistered, MinOutputNotMet, InvalidRequest, InvalidMsg, FulfilmentDeadlineNotMet, SwapOutputInsufficient, NotDelegate, RequestProcessed, InvalidSwitchboard, InvalidRequest, PromisedAmountNotMet, RequestNotProcessed } from "../common/BungeeErrors.sol"; import {Permit2Lib} from "../lib/Permit2Lib.sol"; import {BungeeEvents} from "../common/BungeeEvents.sol"; import {ERC20, SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol"; import {RequestLib} from "../lib/SingleOutputRequestLib.sol"; import {Request, FulfilExec, ExtractExec, ExtractedRequest, FulfilledRequest} from "../common/SingleOutputStructs.sol"; import {BungeeGatewayBase} from "./BungeeGatewayBase.sol"; import {BungeeGatewayStorage} from "./BungeeGatewayStorage.sol"; contract SingleOutputRequestImpl is BungeeGatewayStorage, BungeeGatewayBase, BungeeEvents { using RequestLib for Request; using RequestLib for ExtractExec[]; 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 extractExecs batch of extractions submitted by the transmitter. * @param mofaSignature signature of mofa on the batch. */ function extractRequests(ExtractExec[] calldata extractExecs, bytes calldata mofaSignature) external { // Checks if batch has been authorised by MOFA _checkMofaSig(extractExecs, mofaSignature); // Iterate through extractExec unchecked { for (uint256 i = 0; i < extractExecs.length; i++) { // Check if the promised amount is more than the minOutputAmount if ( // check output amount (extractExecs[i].promisedAmount < extractExecs[i].request.basicReq.minOutputAmount) || // check refuel amount (extractExecs[i].promisedRefuelAmount < extractExecs[i].request.basicReq.refuelAmount) ) revert MinOutputNotMet(); // If a swap is involved the router would receive the swap output tokens specified in request. // If no swap is involved the router would receive the input tokens specified in request. if (extractExecs[i].swapPayload.length > 0) { _swapAndCallRouter(extractExecs[i]); } else { _callRouter(extractExecs[i]); } } } } /** * @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) internal override { uint32 switchboardId = uint32(bytes4(payload)); /// @dev fulfilledAmounts would be output token fulfilled for each request in the batch. hence a 1d array ( bytes32[] memory requestHashes, uint256[] memory fulfilledAmounts, uint256[] memory fulfilledRefuelAmounts ) = abi.decode(payload[4:], (bytes32[], uint256[], uint256[])); unchecked { for (uint256 i = 0; i < requestHashes.length; i++) { _validateAndReleaseSettleRequests( switchboardId, requestHashes[i], fulfilledAmounts[i], fulfilledRefuelAmounts[i] ); } } } /*////////////////////////////////////////////////////////////////////////// INTERNAL SOURCE FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice checks if the mofa signature is valid on the batch submitted by the transmitter. * @param extractExecs batch of extractions submitted by the transmitter. * @param mofaSignature signature of mofa on the batch. */ function _checkMofaSig(ExtractExec[] calldata extractExecs, bytes memory mofaSignature) internal view { // Create the hash of BatchHash bytes32 batchHash = extractExecs.hashOriginBatch(); // Get the signer address signer = AuthenticationLib.authenticate(batchHash, mofaSignature); // Check if addresses match if (signer != MOFA_SIGNER) revert MofaSignatureInvalid(); } /** * @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 the router. * @dev If the swap does not give back enough, revert. * @dev If all is good, the router will be called with relevant details. * @dev Saves the extraction details against the requestHash. * @param extractExec execution submitted by the transmitter for the request. When a request is settled beneficiary will receive funds. */ function _swapAndCallRouter(ExtractExec memory extractExec) internal { // Create the request hash for the submitted request. bytes32 requestHash = extractExec.request.hashOriginRequest(); bool isNativeToken = extractExec.request.swapOutputToken == NATIVE_TOKEN_ADDRESS; // Get the initial balance of the router for the swap output token uint256 initialBalance = isNativeToken ? extractExec.router.balance : ERC20(extractExec.request.swapOutputToken).balanceOf(extractExec.router); // Calls Permit2 to transfer funds from user to swap executor. PERMIT2.permitWitnessTransferFrom( Permit2Lib.toPermit( extractExec.request.basicReq.inputToken, extractExec.request.basicReq.inputAmount, extractExec.request.basicReq.nonce, extractExec.request.basicReq.deadline ), /// @dev transfer tokens to SwapExecutor Permit2Lib.transferDetails(extractExec.request.basicReq.inputAmount, address(SWAP_EXECUTOR)), extractExec.request.basicReq.sender, requestHash, RequestLib.PERMIT2_ORDER_TYPE, extractExec.userSignature ); // Call the swap executor to execute the swap. /// @dev swap output tokens are expected to be sent to the router SWAP_EXECUTOR.executeSwap( extractExec.request.basicReq.inputToken, extractExec.request.basicReq.inputAmount, extractExec.swapRouter, extractExec.swapPayload ); // Get the final balance of the swap output token on the router uint256 swappedAmount = isNativeToken ? extractExec.router.balance - initialBalance : ERC20(extractExec.request.swapOutputToken).balanceOf(extractExec.router) - initialBalance; // Check if the minimum swap output is sufficed after the swap. If not revert. if (swappedAmount < extractExec.request.minSwapOutput) revert SwapOutputInsufficient(); if (!isWhitelisted[extractExec.router]) { _validateAndReduceStake(swappedAmount, extractExec.request.swapOutputToken); } uint256 expiry = block.timestamp + EXPIRY_BUFFER; // Call the router with relevant details IBaseRouter(extractExec.router).execute( swappedAmount, extractExec.request.swapOutputToken, requestHash, expiry, whitelistedReceivers[extractExec.router][extractExec.request.basicReq.destinationChainId], address(FEE_COLLECTOR), extractExec ); // Save the extraction details singleOutputExtractedRequests[requestHash] = ExtractedRequest({ expiry: expiry, router: extractExec.router, sender: extractExec.request.basicReq.sender, delegate: extractExec.request.basicReq.delegate, switchboardId: extractExec.request.basicReq.switchboardId, token: extractExec.request.swapOutputToken, amount: swappedAmount, affiliateFees: extractExec.request.affiliateFees, transmitter: msg.sender, beneficiary: extractExec.beneficiary, promisedAmount: extractExec.promisedAmount, promisedRefuelAmount: extractExec.promisedRefuelAmount }); // Emits Extraction Event emit RequestExtracted(requestHash, SINGLE_OUTPUT_IMPL_ID, msg.sender, abi.encode(extractExec)); } /** * @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 extractExec execution submitted by the transmitter for the request. When a request is settled beneficiary will receive funds. */ function _callRouter(ExtractExec memory extractExec) internal { // If not whitelisted, valiate if the router is part of the protocol and reduce transmitter stake if (!isWhitelisted[extractExec.router]) { _validateAndReduceStake(extractExec.request.basicReq.inputAmount, extractExec.request.basicReq.inputToken); } // Create the request hash for the submitted request. bytes32 requestHash = extractExec.request.hashOriginRequest(); // Calls Permit2 to transfer funds from user to the router. PERMIT2.permitWitnessTransferFrom( Permit2Lib.toPermit( extractExec.request.basicReq.inputToken, extractExec.request.basicReq.inputAmount, extractExec.request.basicReq.nonce, extractExec.request.basicReq.deadline ), Permit2Lib.transferDetails(extractExec.request.basicReq.inputAmount, extractExec.router), extractExec.request.basicReq.sender, requestHash, RequestLib.PERMIT2_ORDER_TYPE, extractExec.userSignature ); uint256 expiry = block.timestamp + EXPIRY_BUFFER; // Call the router with relevant details IBaseRouter(extractExec.router).execute( extractExec.request.basicReq.inputAmount, extractExec.request.basicReq.inputToken, requestHash, expiry, whitelistedReceivers[extractExec.router][extractExec.request.basicReq.destinationChainId], address(FEE_COLLECTOR), extractExec ); // Save the extraction details singleOutputExtractedRequests[requestHash] = ExtractedRequest({ expiry: expiry, router: extractExec.router, sender: extractExec.request.basicReq.sender, delegate: extractExec.request.basicReq.delegate, switchboardId: extractExec.request.basicReq.switchboardId, token: extractExec.request.basicReq.inputToken, amount: extractExec.request.basicReq.inputAmount, affiliateFees: extractExec.request.affiliateFees, transmitter: msg.sender, beneficiary: extractExec.beneficiary, promisedAmount: extractExec.promisedAmount, promisedRefuelAmount: extractExec.promisedRefuelAmount }); // Emits Extraction Event emit RequestExtracted(requestHash, SINGLE_OUTPUT_IMPL_ID, msg.sender, abi.encode(extractExec)); } /** * @notice validates the settlement details against the request. * @param switchboardId id of the switchboard that received the msg. * @param requestHash hash of the request that needs to be settled. * @param fulfilledAmount amount sent to the receiver on the destination. */ function _validateAndReleaseSettleRequests( uint32 switchboardId, bytes32 requestHash, uint256 fulfilledAmount, uint256 fulfilledRefuelAmount ) internal { // Check if the extraction exists and the switchboard id is correct. ExtractedRequest memory eReq = singleOutputExtractedRequests[requestHash]; // Check if the request is valid. // Check if request has already been settled. if (eReq.sender == address(0)) revert InvalidRequest(); if (eReq.switchboardId != switchboardId) revert InvalidSwitchboard(); // Check if the fulfilment was done correctly. // Check if the request was fulfilled: output token & refuel amount if ((eReq.promisedAmount > fulfilledAmount) || (eReq.promisedRefuelAmount > fulfilledRefuelAmount)) revert PromisedAmountNotMet(); // Get the beneficiary amount to settle the request. // Checks if there was affiliate fees involved. uint256 beneficiaryAmount = AffiliateFeesLib.getAmountAfterFee(eReq.amount, eReq.affiliateFees); if (isWhitelisted[eReq.router]) { // Settle Fee. if (eReq.amount > beneficiaryAmount) { FEE_COLLECTOR.settleFee(requestHash); } // track the amount to be settled beneficiarySettlements[eReq.beneficiary][eReq.router][eReq.token] += beneficiaryAmount; } else { // replenish transmitter stake by input amount _increaseCapacity(eReq.transmitter, eReq.token, eReq.amount); } // Delete the origin execution. delete singleOutputExtractedRequests[requestHash]; // Emits Settlement event emit RequestSettled(requestHash); } /** * @notice this function can be called by user on source chain to revoke order after fulfil deadline has passed * @dev Asks router to send back escrowed funds to commander in case of RFQ. * @dev Slash the stake from the transmitter to pay back to the user. * @dev Funds routed via whitelisted routers cannot be withdrawn on source. Withdraw on destination can be done for whitelisted routes. * @param requestHash hash of the request */ function withdrawRequestOnOrigin(bytes32 requestHash) external { ExtractedRequest memory eReq = singleOutputExtractedRequests[requestHash]; // Check if the request is valid. if (eReq.sender == address(0)) revert InvalidRequest(); // Checks deadline of request fulfilment and if its exceeded, if (block.timestamp < eReq.expiry) revert FulfilmentDeadlineNotMet(); if (isWhitelisted[eReq.router]) { // Checks if there was affiliate fees involved. uint256 routerAmount = AffiliateFeesLib.getAmountAfterFee(eReq.amount, eReq.affiliateFees); FEE_COLLECTOR.refundFee(requestHash, eReq.sender); // Ask router to transfer funds back to the user IBaseRouter(eReq.router).releaseFunds(eReq.token, routerAmount, eReq.sender); } else { // Withdraw transmitter stake and give back to the user. /// @dev transmitter capacity would already be reduced when the request was extracted /// no need to change the capacity any way then STAKE_VAULT.withdrawStake(eReq.token, eReq.amount, eReq.sender); } // Emits Withdraw event emit WithdrawOnOrigin(requestHash, eReq.token, eReq.amount, eReq.sender); // Stores WithdrawnRequest withdrawnRequests[requestHash] = true; // Delete the origin execution delete singleOutputExtractedRequests[requestHash]; } /*////////////////////////////////////////////////////////////////////////// DESTINATION FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Performs fulfilment of a batch of requests * @dev Called by transmitter to fulfil a request * @dev Calculates and tracks destination hash of fulfilled requests * @dev Can fulfil a batch of requests * @dev Checks if provided router contract is registered with Bungee protocol * @param fulfilExecs Array of FulfilExec */ function fulfilRequests(FulfilExec[] calldata fulfilExecs) external payable { // Will be used to check if the msg value was sufficient at the end. uint256 nativeAmount = 0; // Iterate through the array of fulfil execs. for (uint256 i = 0; i < fulfilExecs.length; i++) { FulfilExec memory fulfilExec = fulfilExecs[i]; // Calculate the request hash. Being tracked on singleOutputFulfilledRequests bytes32 requestHash = fulfilExec.request.hashDestinationRequest(); // 1.a Check if the command is already fulfilled / cancelled if (singleOutputFulfilledRequests[requestHash].processed) revert RequestProcessed(); // 1.c Check if the provided router address is part of the Bungee protocol if (!isBungeeRouter(fulfilExec.fulfilRouter)) revert RouterNotRegistered(); // 1.d Check if promisedOutput amounts are more than minOutput amounts if ( // check output amount (fulfilExec.fulfilAmount < fulfilExec.request.basicReq.minOutputAmount) || // check refuel amount (fulfilExec.refuelFulfilAmount < fulfilExec.request.basicReq.refuelAmount) ) revert MinOutputNotMet(); // 2. Call the fulfil function on the router IBaseRouter(fulfilExec.fulfilRouter).fulfil{value: fulfilExec.msgValue}( requestHash, fulfilExec, msg.sender ); nativeAmount += fulfilExec.msgValue; // 4. BungeeGateway stores order hash and its outputToken, promisedOutput singleOutputFulfilledRequests[requestHash] = FulfilledRequest({ fulfilledAmount: fulfilExec.fulfilAmount, fulfilledRefuelAmount: fulfilExec.refuelFulfilAmount, processed: true }); // Emits Fulfilment Event emit RequestFulfilled(requestHash, SINGLE_OUTPUT_IMPL_ID, msg.sender, abi.encode(fulfilExec)); } if (msg.value < nativeAmount) revert InsufficientNativeAmount(); } /** * @notice Sends a settlement message back towards source to settle the requests. * @param requestHashes Array of request hashes to be settled. * @param gasLimit Gas limit to be used on the message receiving chain. * @param chainSlug Chain slug used in Socket to send the message towards i.e, source chain id * @param switchboardId id of the switchboard to use. switchboardIds of all requests in the batch must match */ function settleRequests( bytes32[] calldata requestHashes, uint256 gasLimit, uint32 chainSlug, uint32 switchboardId ) external payable { // Create an empty array of fulfilled amounts. /// @dev fulfilledAmounts would be output token fulfilled for each request in the batch. hence a 1d array uint256[] memory fulfilledAmounts = new uint256[](requestHashes.length); uint256[] memory fulfilledRefuelAmounts = new uint256[](requestHashes.length); // Loop through the requestHashes and set fulfilled amounts unchecked { for (uint256 i = 0; i < requestHashes.length; i++) { FulfilledRequest memory fReq = singleOutputFulfilledRequests[requestHashes[i]]; // check if request already processed if (!fReq.processed) revert RequestNotProcessed(); // Get the amount send to he receiver of the command and push into array fulfilledAmounts[i] = fReq.fulfilledAmount; fulfilledRefuelAmounts[i] = fReq.fulfilledRefuelAmount; } } // Call the switchboard router to send the message. SWITCHBOARD_ROUTER.sendOutboundMsg{value: msg.value}( chainSlug, switchboardId, SINGLE_OUTPUT_IMPL_ID, gasLimit, abi.encode(requestHashes, fulfilledAmounts, fulfilledRefuelAmounts) ); emit RequestsSettledOnDestination(requestHashes, SINGLE_OUTPUT_IMPL_ID, msg.sender, msg.value); } function withdrawRequestOnDestination( address router, Request calldata request, bytes calldata withdrawRequestData ) external payable { // generate the requestHash bytes32 requestHash = request.hashDestinationRequest(); // checks if the caller is the delegate if (msg.sender != request.basicReq.delegate) revert NotDelegate(); // Check if the command is already fulfilled / cancelled if (singleOutputFulfilledRequests[requestHash].processed) revert RequestProcessed(); // mark request as cancelled singleOutputFulfilledRequests[requestHash] = FulfilledRequest({ fulfilledAmount: 0, fulfilledRefuelAmount: 0, processed: true }); // check router is in system if (!isBungeeRouter(router)) revert RouterNotRegistered(); /// @dev router should know if the request hash is not supposed to be handled by it IBaseRouter(router).withdrawRequestOnDestination(request, withdrawRequestData); // TODO : need to add an event here } }
// 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(); error ReleaseFundsNotImplemented();
// 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; 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: UNLICENSED pragma solidity ^0.8.17; import {IBaseRouter} from "./IBaseRouter.sol"; import {FulfilExec, ExtractExec, Request} from "../common/SingleOutputStructs.sol"; interface IBaseRouterSingleOutput is IBaseRouter { function execute( uint256 amount, address inputToken, bytes32 requestHash, uint256 expiry, address receiverContract, address feeCollector, ExtractExec memory exec ) external; function fulfil(bytes32 requestHash, FulfilExec calldata fulfilExec, address transmitter) external payable; function withdrawRequestOnDestination(Request calldata request, bytes calldata withdrawRequestData) external; }
// 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 {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
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FulfilmentDeadlineNotMet","type":"error"},{"inputs":[],"name":"InsufficientCapacity","type":"error"},{"inputs":[],"name":"InsufficientNativeAmount","type":"error"},{"inputs":[],"name":"InvalidMsg","type":"error"},{"inputs":[],"name":"InvalidRequest","type":"error"},{"inputs":[],"name":"InvalidStake","type":"error"},{"inputs":[],"name":"InvalidSwitchboard","type":"error"},{"inputs":[],"name":"MinOutputNotMet","type":"error"},{"inputs":[],"name":"MofaSignatureInvalid","type":"error"},{"inputs":[],"name":"NotDelegate","type":"error"},{"inputs":[],"name":"OnlyNominee","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"PromisedAmountNotMet","type":"error"},{"inputs":[],"name":"RequestNotProcessed","type":"error"},{"inputs":[],"name":"RequestProcessed","type":"error"},{"inputs":[],"name":"RouterAlreadyRegistered","type":"error"},{"inputs":[],"name":"RouterAlreadyWhitelisted","type":"error"},{"inputs":[],"name":"RouterNotRegistered","type":"error"},{"inputs":[],"name":"SwapOutputInsufficient","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":"originChainId","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","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":"delegate","type":"address"},{"internalType":"address","name":"bungeeGateway","type":"address"},{"internalType":"uint32","name":"switchboardId","type":"uint32"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"uint256","name":"refuelAmount","type":"uint256"}],"internalType":"struct BasicRequest","name":"basicReq","type":"tuple"},{"internalType":"address","name":"swapOutputToken","type":"address"},{"internalType":"uint256","name":"minSwapOutput","type":"uint256"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"bytes","name":"affiliateFees","type":"bytes"}],"internalType":"struct Request","name":"request","type":"tuple"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"promisedAmount","type":"uint256"},{"internalType":"uint256","name":"promisedRefuelAmount","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"},{"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 ExtractExec[]","name":"extractExecs","type":"tuple[]"},{"internalType":"bytes","name":"mofaSignature","type":"bytes"}],"name":"extractRequests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","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":"delegate","type":"address"},{"internalType":"address","name":"bungeeGateway","type":"address"},{"internalType":"uint32","name":"switchboardId","type":"uint32"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"uint256","name":"refuelAmount","type":"uint256"}],"internalType":"struct BasicRequest","name":"basicReq","type":"tuple"},{"internalType":"address","name":"swapOutputToken","type":"address"},{"internalType":"uint256","name":"minSwapOutput","type":"uint256"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"bytes","name":"affiliateFees","type":"bytes"}],"internalType":"struct Request","name":"request","type":"tuple"},{"internalType":"address","name":"fulfilRouter","type":"address"},{"internalType":"uint256","name":"fulfilAmount","type":"uint256"},{"internalType":"uint256","name":"refuelFulfilAmount","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"},{"internalType":"uint256","name":"msgValue","type":"uint256"}],"internalType":"struct FulfilExec[]","name":"fulfilExecs","type":"tuple[]"}],"name":"fulfilRequests","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":"bytes32[]","name":"requestHashes","type":"bytes32[]"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"chainSlug","type":"uint32"},{"internalType":"uint32","name":"switchboardId","type":"uint32"}],"name":"settleRequests","outputs":[],"stateMutability":"payable","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":"router","type":"address"},{"components":[{"components":[{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","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":"delegate","type":"address"},{"internalType":"address","name":"bungeeGateway","type":"address"},{"internalType":"uint32","name":"switchboardId","type":"uint32"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"uint256","name":"refuelAmount","type":"uint256"}],"internalType":"struct BasicRequest","name":"basicReq","type":"tuple"},{"internalType":"address","name":"swapOutputToken","type":"address"},{"internalType":"uint256","name":"minSwapOutput","type":"uint256"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"bytes","name":"affiliateFees","type":"bytes"}],"internalType":"struct Request","name":"request","type":"tuple"},{"internalType":"bytes","name":"withdrawRequestData","type":"bytes"}],"name":"withdrawRequestOnDestination","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestHash","type":"bytes32"}],"name":"withdrawRequestOnOrigin","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
60a06040523480156200001157600080fd5b5060405162005610380380620056108339810160408190526200003491620000c9565b818181620000428162000059565b506001600160a01b03166080525062000101915050565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b80516001600160a01b0381168114620000c457600080fd5b919050565b60008060408385031215620000dd57600080fd5b620000e883620000ac565b9150620000f860208401620000ac565b90509250929050565b6080516154e56200012b6000396000818161057f015281816121d501526128a201526154e56000f3fe6080604052600436106102675760003560e01c8063733957f811610144578063a42dce80116100b6578063d9e9a7be1161007a578063d9e9a7be146107cb578063df2ebdbb146107de578063e1282c5c14610806578063e9899ed21461084a578063f36ba4d81461086a578063f82814861461088a57600080fd5b8063a42dce801461074f578063ae3100c01461076f578063b746078a14610785578063cc6dc63a14610798578063cf376c1d146107b857600080fd5b80637f660b01116101085780637f660b011461068457806380f7013e146106a4578063823d0088146106dc5780638da5cb5b146106f1578063967aef081461070f5780639ed0cb131461072f57600080fd5b8063733957f8146105c15780637373161f146105e157806374f8d3fd1461060157806376479d1b14610644578063795d86b81461066457600080fd5b80633af32abf116101dd5780634c7a7732116101a15780634c7a7732146104d05780635b94db27146104fd5780636a0706db1461051d5780636a7372da1461053d5780636afdd8501461056d57806370b55089146105a157600080fd5b80633af32abf146104135780633bd1adec146104435780633cbc7eaa146104585780633cf3c2b61461047f5780633de408a11461049257600080fd5b806312f07c251161022f57806312f07c25146103395780631e789c361461035957806320798eb7146103a257806320f99c0a146103b557806320ff430b146103d357806331feeadd146103f357600080fd5b8063091b89461461026c5780630b3458791461028e5780630c0a0ccb146102cb5780630cb352e0146102f95780630e4bfd6e14610319575b600080fd5b34801561027857600080fd5b5061028c610287366004613b4b565b6108aa565b005b34801561029a57600080fd5b506004546102ae906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d757600080fd5b506102eb6102e6366004613b80565b610cb7565b6040519081526020016102c2565b34801561030557600080fd5b506005546102ae906001600160a01b031681565b34801561032557600080fd5b506003546102ae906001600160a01b031681565b34801561034557600080fd5b506002546102ae906001600160a01b031681565b34801561036557600080fd5b50610392610374366004613bb3565b6001600160a01b03166000908152600c602052604090205460ff1690565b60405190151581526020016102c2565b61028c6103b0366004613bd5565b610ce4565b3480156103c157600080fd5b506001546001600160a01b03166102ae565b3480156103df57600080fd5b5061028c6103ee366004613bff565b610e14565b3480156103ff57600080fd5b5061028c61040e366004613c3b565b610e4a565b34801561041f57600080fd5b5061039261042e366004613bb3565b600d6020526000908152604090205460ff1681565b34801561044f57600080fd5b5061028c610f13565b34801561046457600080fd5b5061046d600181565b60405160ff90911681526020016102c2565b61028c61048d366004613cdd565b610f49565b34801561049e57600080fd5b506102eb6104ad366004613c3b565b601060209081526000938452604080852082529284528284209052825290205481565b3480156104dc57600080fd5b506104f06104eb366004613b4b565b611195565b6040516102c29190613d9a565b34801561050957600080fd5b5061028c610518366004613bb3565b61133f565b34801561052957600080fd5b5061028c610538366004613bb3565b6113b4565b34801561054957600080fd5b50610392610558366004613b4b565b600f6020526000908152604090205460ff1681565b34801561057957600080fd5b506102ae7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ad57600080fd5b5061028c6105bc366004613ec6565b611401565b3480156105cd57600080fd5b5061028c6105dc366004613bb3565b6115e4565b3480156105ed57600080fd5b5061028c6105fc366004613b4b565b611631565b34801561060d57600080fd5b506102ae61061c366004613bd5565b6001600160a01b039182166000908152600b6020908152604080832093835292905220541690565b34801561065057600080fd5b5061028c61065f366004613bb3565b611661565b34801561067057600080fd5b5061028c61067f366004613bb3565b61172f565b34801561069057600080fd5b506006546102ae906001600160a01b031681565b3480156106b057600080fd5b506102eb6106bf366004613b80565b600e60209081526000928352604080842090915290825290205481565b3480156106e857600080fd5b5061046d600281565b3480156106fd57600080fd5b506000546001600160a01b03166102ae565b34801561071b57600080fd5b5061028c61072a366004613bd5565b61179d565b34801561073b57600080fd5b5061028c61074a366004613f31565b611853565b34801561075b57600080fd5b5061028c61076a366004613bb3565b6118bb565b34801561077b57600080fd5b506102eb60085481565b61028c610793366004613f64565b611908565b3480156107a457600080fd5b5061028c6107b3366004613bb3565b61193d565b61028c6107c6366004613fa5565b61198a565b61028c6107d9366004613fda565b611bef565b3480156107ea57600080fd5b506102ae73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561081257600080fd5b50610826610821366004613b4b565b611d5d565b604080518251815260208084015190820152918101511515908201526060016102c2565b34801561085657600080fd5b5061028c610865366004613bb3565b611dc1565b34801561087657600080fd5b5061028c610885366004613bb3565b611e0e565b34801561089657600080fd5b506007546102ae906001600160a01b031681565b6000818152600a602081815260408084208151610180810183528154815260018201546001600160a01b0390811694820194909452600282015484169281019290925260038101548084166060840152600160a01b900463ffffffff1660808301526004810154831660a08301526005810154831660c0830152600681015490921660e082015260078201546101008201526008820154610120820152600982015461014082015291810180546101608401919061096790614040565b80601f016020809104026020016040519081016040528092919081815260200182805461099390614040565b80156109e05780601f106109b5576101008083540402835291602001916109e0565b820191906000526020600020905b8154815290600101906020018083116109c357829003601f168201915b5050509190925250505060408101519091506001600160a01b0316610a18576040516341abc80160e01b815260040160405180910390fd5b8051421015610a3a57604051630888f67560e41b815260040160405180910390fd5b6020808201516001600160a01b03166000908152600d909152604090205460ff1615610b56576000610a76826101000151836101600151611e5b565b6006546040848101519051632ad7b7d360e11b8152600481018790526001600160a01b03918216602482015292935016906355af6fa690604401600060405180830381600087803b158015610aca57600080fd5b505af1158015610ade573d6000803e3d6000fd5b5050505081602001516001600160a01b03166362524dd78360a001518385604001516040518463ffffffff1660e01b8152600401610b1e9392919061407a565b600060405180830381600087803b158015610b3857600080fd5b505af1158015610b4c573d6000803e3d6000fd5b5050505050610bcb565b60075460a08201516101008301516040808501519051632385922d60e01b81526001600160a01b0390941693632385922d93610b98939092909160040161407a565b600060405180830381600087803b158015610bb257600080fd5b505af1158015610bc6573d6000803e3d6000fd5b505050505b817f5785ffbb8ccb1fbfff4aaf0bf7419c43517c350880dabf3644dfd1d05f1186938260a001518361010001518460400151604051610c0c9392919061407a565b60405180910390a26000828152600f60209081526040808320805460ff19166001908117909155600a9283905290832083815590810180546001600160a01b0319908116909155600282018054821690556003820180546001600160c01b0319169055600482018054821690556005820180548216905560068201805490911690556007810183905560088101839055600981018390559190610cb190830182613afd565b50505050565b6001600160a01b038083166000908152600e60209081526040808320938516835292905220545b92915050565b336000908152600e602090815260408083206001600160a01b0386168452909152902054610d139082906140b3565b336000908152600e602090815260408083206001600160a01b03871680855292529091209190915573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed1901610df457803414610d7657604051634eba4d4960e11b815260040160405180910390fd5b6007546040516000916001600160a01b03169061138890849084818181858888f193505050503d8060008114610dc8576040519150601f19603f3d011682016040523d82523d6000602084013e610dcd565b606091505b5050905080610def576040516312171d8360e31b815260040160405180910390fd5b505050565b600754610e10906001600160a01b038481169133911684611ef3565b5050565b6000546001600160a01b03163314610e3f57604051635fc483c560e01b815260040160405180910390fd5b610def838284611f8d565b6001600160a01b03808416600090815260106020908152604080832086851684528252808320938516835292905220548015610cb1576001600160a01b03808516600090815260106020908152604080832087851680855290835281842094871684529390915280822091909155516362524dd760e01b81526362524dd790610edb9085908590899060040161407a565b600060405180830381600087803b158015610ef557600080fd5b505af1158015610f09573d6000803e3d6000fd5b5050505050505050565b6001546001600160a01b03163314610f3e57604051637c91ccdd60e01b815260040160405180910390fd5b610f473361203f565b565b6000846001600160401b03811115610f6357610f636140c6565b604051908082528060200260200182016040528015610f8c578160200160208202803683370190505b5090506000856001600160401b03811115610fa957610fa96140c6565b604051908082528060200260200182016040528015610fd2578160200160208202803683370190505b50905060005b868110156110a9576000600960008a8a85818110610ff857610ff86140dc565b602090810292909201358352508181019290925260409081016000208151606081018352815481526001820154938101939093526002015460ff16151590820181905290915061105b5760405163a4d9007d60e01b815260040160405180910390fd5b8060000151848381518110611072576110726140dc565b6020026020010181815250508060200151838381518110611095576110956140dc565b602090810291909101015250600101610fd8565b50600360009054906101000a90046001600160a01b03166001600160a01b0316635813c9c534868660018a8d8d8a8a6040516020016110eb949392919061415f565b6040516020818303038152906040526040518763ffffffff1660e01b815260040161111a9594939291906141a4565b6000604051808303818588803b15801561113357600080fd5b505af1158015611147573d6000803e3d6000fd5b50505050507f3e09b55b6efb54718ae4486c6229eaf5afca42c1aed76e189d9cfaeb3b539f4e8787600133346040516111849594939291906141dc565b60405180910390a150505050505050565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101919091526000828152600a60208181526040928390208351610180810185528154815260018201546001600160a01b0390811693820193909352600282015483169481019490945260038101548083166060860152600160a01b900463ffffffff1660808501526004810154821660a08501526005810154821660c0850152600681015490911660e08401526007810154610100840152600881015461012084015260098101546101408401529081018054610160840191906112b690614040565b80601f01602080910402602001604051908101604052809291908181526020018280546112e290614040565b801561132f5780601f106113045761010080835404028352916020019161132f565b820191906000526020600020905b81548152906001019060200180831161131257829003601f168201915b5050505050815250509050919050565b6000546001600160a01b0316331461136a57604051635fc483c560e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b6000546001600160a01b031633146113df57604051635fc483c560e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b611442848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061209292505050565b60005b838110156115dd5784848281811061145f5761145f6140dc565b90506020028101906114719190614219565b61147b908061423a565b6101800135858583818110611492576114926140dc565b90506020028101906114a49190614219565b60400135108061150c57508484828181106114c1576114c16140dc565b90506020028101906114d39190614219565b6114dd908061423a565b6101a001358585838181106114f4576114f46140dc565b90506020028101906115069190614219565b60600135105b1561152a5760405163308657c360e21b815260040160405180910390fd5b600085858381811061153e5761153e6140dc565b90506020028101906115509190614219565b61155e9060a0810190614251565b905011156115a05761159b85858381811061157b5761157b6140dc565b905060200281019061158d9190614219565b61159690614619565b6120e5565b6115d5565b6115d58585838181106115b5576115b56140dc565b90506020028101906115c79190614219565b6115d090614619565b61282d565b600101611445565b5050505050565b6000546001600160a01b0316331461160f57604051635fc483c560e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461165c57604051635fc483c560e01b815260040160405180910390fd5b600855565b6000546001600160a01b0316331461168c57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600d602052604090205460ff16156116c65760405163406c5bd360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff161561170057604051633ba24ff960e11b815260040160405180910390fd5b6001600160a01b0381166000908152600d60205260409020805460ff1916600117905561172c81612d86565b50565b6000546001600160a01b0316331461175a57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff161561179457604051633ba24ff960e11b815260040160405180910390fd5b61172c81612d86565b336000908152600e602090815260408083206001600160a01b03861684529091529020546117cc908290614625565b336000818152600e602090815260408083206001600160a01b038881168552925291829020939093556007549051632385922d60e01b8152921691632385922d9161181d918691869160040161407a565b600060405180830381600087803b15801561183757600080fd5b505af115801561184b573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461187e57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b039081166000908152600b60209081526040808320948352939052919091208054919092166001600160a01b0319909116179055565b6000546001600160a01b031633146118e657604051635fc483c560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b0316331461193357604051631bd147a760e01b815260040160405180910390fd5b610e108282612daa565b6000546001600160a01b0316331461196857604051635fc483c560e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b82811015611bcd5760008484838181106119aa576119aa6140dc565b90506020028101906119bc9190614638565b6119c59061464e565b905060006119d68260000151612e53565b60008181526009602052604090206002015490915060ff1615611a0c5760405163234bc0ff60e21b815260040160405180910390fd5b611a3282602001516001600160a01b03166000908152600c602052604090205460ff1690565b611a4f576040516315812c6160e11b815260040160405180910390fd5b815151610180015160408301511080611a7257508151516101a001516060830151105b15611a905760405163308657c360e21b815260040160405180910390fd5b81602001516001600160a01b031663da2de3448360a001518385336040518563ffffffff1660e01b8152600401611ac993929190614889565b6000604051808303818588803b158015611ae257600080fd5b505af1158015611af6573d6000803e3d6000fd5b50505050508160a0015184611b0b91906140b3565b6040805160608082018352858301518252850151602080830191825260018385018181526000888152600984528690209451855592518482015591516002909301805460ff191693151593909317909255915192965083927fd83e4fbd120e768f3bb813ecfa1a2b16c323fa7dfa07db1cd6434b3cbc97bc7592913391611b94918891016148ba565b60408051601f1981840301815290829052611bb09392916148cd565b60405180910390a250508080611bc5906148fa565b91505061198e565b5080341015610def57604051637bf261fb60e01b815260040160405180910390fd5b6000611c02611bfd85614913565b612e53565b9050611c1460e0850160c08601613bb3565b6001600160a01b0316336001600160a01b031614611c4557604051631db3b85960e01b815260040160405180910390fd5b60008181526009602052604090206002015460ff1615611c785760405163234bc0ff60e21b815260040160405180910390fd5b604080516060810182526000808252602080830182815260018486018181528785526009845286852095518655915190850155516002909301805460ff1916931515939093179092556001600160a01b0388168152600c909152205460ff16611cf4576040516315812c6160e11b815260040160405180910390fd5b604051632757107160e11b81526001600160a01b03861690634eae20e290611d249087908790879060040161498d565b600060405180830381600087803b158015611d3e57600080fd5b505af1158015611d52573d6000803e3d6000fd5b505050505050505050565b611d83604051806060016040528060008152602001600081526020016000151581525090565b506000908152600960209081526040918290208251606081018452815481526001820154928101929092526002015460ff1615159181019190915290565b6000546001600160a01b03163314611dec57604051635fc483c560e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314611e3957604051635fc483c560e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008084511115611eea5760008451601a14611e8d57604051634115207f60e01b815260040160405180910390fd5b611e98856014612f3c565b9050611ea5856000612f99565b925065ffffffffffff811615611ee857662386f26fc10000611ecf65ffffffffffff831688614b4d565b611ed99190614b64565b9150611ee58287614625565b95505b505b50929392505050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806115dd5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161202b576000816001600160a01b03168361138890604051600060405180830381858888f193505050503d8060008114612004576040519150601f19603f3d011682016040523d82523d6000602084013e612009565b606091505b5050905080610cb1576040516312171d8360e31b815260040160405180910390fd5b610def6001600160a01b0384168284612ffe565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60006120a66120a18486614ba9565b61307f565b905060006120b4828461310b565b6002549091506001600160a01b038083169116146115dd57604051633c6ae50160e11b815260040160405180910390fd5b60006120f4826000015161312b565b8251602001519091506001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1460008161219e578351602090810151908501516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015612175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121999190614c21565b6121ae565b83602001516001600160a01b0316315b84515161012081015161014082015160608301516040909301519394506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363137c29fe9361220793929161319b565b8651516101400151600454604080518082018252600080825260209182015281518083019092526001600160a01b0390921681529081019190915287515160800151604051889061225a90602001614c3a565b60405160208183030381529060405260405160200161227890614deb565b60408051601f19818403018152908290526122969291602001614e9a565b60408051601f1981840301815260608301909152602e80835290919061548260208301396040516020016122cb929190614ec9565b6040516020818303038152906040528a60e001516040518763ffffffff1660e01b815260040161230096959493929190614f17565b600060405180830381600087803b15801561231a57600080fd5b505af115801561232e573d6000803e3d6000fd5b5050600480548751516101208101516101409091015160c08a015160a08b015160405163017c1d7560e31b81526001600160a01b039095169750630be0eba8965061238195939492939192909101614fba565b600060405180830381600087803b15801561239b57600080fd5b505af11580156123af573d6000803e3d6000fd5b50505050600082612443578451602090810151908601516040516370a0823160e01b81526001600160a01b039182166004820152849291909116906370a0823190602401602060405180830381865afa158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614c21565b61243e9190614625565b61245d565b8185602001516001600160a01b03163161245d9190614625565b85516040015190915081101561248657604051633453a1e760e01b815260040160405180910390fd5b6020808601516001600160a01b03166000908152600d909152604090205460ff166124bd576124bd818660000151602001516131fd565b6000600854426124cd91906140b3565b60208088015188518201516001600160a01b039182166000818152600b855260408082208d51518701518352909552849020546006549451633ed33c7f60e01b81529596509094633ed33c7f94612538948994938d938a939183169291909116908f906004016150c3565b600060405180830381600087803b15801561255257600080fd5b505af1158015612566573d6000803e3d6000fd5b5050505060405180610180016040528082815260200187602001516001600160a01b03168152602001876000015160000151608001516001600160a01b0316815260200187600001516000015160c001516001600160a01b03168152602001876000015160000151610100015163ffffffff1681526020018760000151602001516001600160a01b03168152602001336001600160a01b031681526020018761010001516001600160a01b031681526020018381526020018760400151815260200187606001518152602001876000015160800151815250600a60008781526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061010082015181600701556101208201518160080155610140820151816009015561016082015181600a0190816127c79190615151565b50905050847f14a241d5b404d2061ceb9a847972acfd690983f1d8a0fef9779b8191aa1b7ef2600133896040516020016128019190615210565b60408051601f198184030181529082905261281d9392916148cd565b60405180910390a2505050505050565b6020808201516001600160a01b03166000908152600d909152604090205460ff1661286c578051516101408101516101209091015161286c91906131fd565b600061287b826000015161312b565b82515161012081015161014082015160608301516040909301519394506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363137c29fe936128d493929161319b565b845151610140015160208087015160408051808201825260008082529084015280518082019091526001600160a01b0390911681529081019190915285515160800151604051869061292890602001614c3a565b60405160208183030381529060405260405160200161294690614deb565b60408051601f19818403018152908290526129649291602001614e9a565b60408051601f1981840301815260608301909152602e8083529091906154826020830139604051602001612999929190614ec9565b6040516020818303038152906040528860e001516040518763ffffffff1660e01b81526004016129ce96959493929190614f17565b600060405180830381600087803b1580156129e857600080fd5b505af11580156129fc573d6000803e3d6000fd5b50505050600060085442612a1091906140b3565b602080850151855151610140810151610120909101516001600160a01b039283166000818152600b865260408082208b51518801518352909652859020546006549551633ed33c7f60e01b81529697509095633ed33c7f95612a82958a938a9390821692909116908c906004016150c3565b600060405180830381600087803b158015612a9c57600080fd5b505af1158015612ab0573d6000803e3d6000fd5b5050505060405180610180016040528082815260200184602001516001600160a01b03168152602001846000015160000151608001516001600160a01b0316815260200184600001516000015160c001516001600160a01b03168152602001846000015160000151610100015163ffffffff16815260200184600001516000015161012001516001600160a01b03168152602001336001600160a01b031681526020018461010001516001600160a01b03168152602001846000015160000151610140015181526020018460400151815260200184606001518152602001846000015160800151815250600a60008481526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061010082015181600701556101208201518160080155610140820151816009015561016082015181600a019081612d239190615151565b50905050817f14a241d5b404d2061ceb9a847972acfd690983f1d8a0fef9779b8191aa1b7ef260013386604051602001612d5d9190615210565b60408051601f1981840301815290829052612d799392916148cd565b60405180910390a2505050565b6001600160a01b03166000908152600c60205260409020805460ff19166001179055565b6000612db68284615223565b60e01c905060008080612dcc8560048189615253565b810190612dd991906152e3565b92509250925060005b8351811015612e4a57612e4285858381518110612e0157612e016140dc565b6020026020010151858481518110612e1b57612e1b6140dc565b6020026020010151858581518110612e3557612e356140dc565b6020026020010151613232565b600101612de2565b50505050505050565b6000604051602001612e6490614deb565b604051602081830303815290604052604051602001612e8290614c3a565b60408051601f1981840301815290829052612ea09291602001614e9a565b60405160208183030381529060405280519060200120612ec383600001516135dc565b836020015184604001518560600151866080015180519060200120604051602001612f1f9695949392919095865260208601949094526001600160a01b039290921660408501526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b6000612f498260066140b3565b83511015612f905760405162461bcd60e51b8152602060048201526014602482015273746f55696e7434385f6f75744f66426f756e647360601b6044820152606401611f84565b50016006015190565b6000612fa68260146140b3565b83511015612fee5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401611f84565b500160200151600160601b900490565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610cb15760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611f84565b60007f0229eabb7e69af818c010d3333cd777014bff2c06ac717d3e0df036a6e9ff570815b835181101561310457816130d08583815181106130c3576130c36140dc565b6020026020010151613686565b60408051602081019390935282015260600160408051601f19818403018152919052805160209091012091506001016130a4565b5092915050565b600080613117846138b0565b905061312381846138eb565b949350505050565b600060405160200161313c90614deb565b60405160208183030381529060405260405160200161315a90614c3a565b60408051601f19818403018152908290526131789291602001614e9a565b60405160208183030381529060405280519060200120612ec3836000015161396a565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a0810182526001600160a01b039590951660608601908152608086019490945292845260208401919091529082015290565b816132083383610cb7565b101561322757604051632e77ac1d60e11b815260040160405180910390fd5b610e103382846139f6565b6000838152600a602081815260408084208151610180810183528154815260018201546001600160a01b0390811694820194909452600282015484169281019290925260038101548084166060840152600160a01b900463ffffffff1660808301526004810154831660a08301526005810154831660c0830152600681015490921660e08201526007820154610100820152600882015461012082015260098201546101408201529181018054610160840191906132ef90614040565b80601f016020809104026020016040519081016040528092919081815260200182805461331b90614040565b80156133685780601f1061333d57610100808354040283529160200191613368565b820191906000526020600020905b81548152906001019060200180831161334b57829003601f168201915b5050509190925250505060408101519091506001600160a01b03166133a0576040516341abc80160e01b815260040160405180910390fd5b8463ffffffff16816080015163ffffffff16146133d05760405163f63c9e4d60e01b815260040160405180910390fd5b8281610120015111806133e7575081816101400151115b15613405576040516330be5d5d60e11b815260040160405180910390fd5b600061341b826101000151836101600151611e5b565b6020808401516001600160a01b03166000908152600d909152604090205490915060ff1615613509578082610100015111156134b057600654604051630710376f60e11b8152600481018790526001600160a01b0390911690630e206ede90602401600060405180830381600087803b15801561349757600080fd5b505af11580156134ab573d6000803e3d6000fd5b505050505b60e08201516001600160a01b0390811660009081526010602090815260408083208287015185168452825280832060a0870151909416835292905290812080548392906134fe9084906140b3565b909155506135219050565b6135218260c001518360a00151846101000151613a58565b6000858152600a6020819052604082208281556001810180546001600160a01b0319908116909155600282018054821690556003820180546001600160c01b03191690556004820180548216905560058201805482169055600682018054909116905560078101839055600881018390556009810183905591906135a790830182613afd565b505060405185907f7eea86cc10df3b8a859a99d48d6858b1128a479f035d0223cf9dd929f37c607990600090a2505050505050565b60006040516020016135ed90614c3a565b604051602081830303815290604052805190602001208260000151468460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e61018001518f6101a001516040516020016136689e9d9c9b9a999897969594939291906153bf565b60408051601f1981840301815290829052612f1f929160200161545b565b6040516b08af0e8e4c2c6e88af0cac6560a31b60208201526f14995c5d595cdd081c995c5d595cdd0b60821b602c8201526e1859191c995cdcc81c9bdd5d195c8b608a1b603c8201527f75696e743235362070726f6d69736564416d6f756e742c000000000000000000604b8201527f75696e743235362070726f6d6973656452656675656c416d6f756e742c000000606282015270189e5d195cc81c9bdd5d195c91185d184b607a1b607f82015271189e5d195cc81cddd85c14185e5b1bd8590b60721b6090820152721859191c995cdcc81cddd85c149bdd5d195c8b606a1b60a282015273189e5d195cc81d5cd95c94da59db985d1d5c994b60621b60b582015273616464726573732062656e65666963696172792960601b60c982015260009060dd016040516020818303038152906040526040516020016137ca90614deb565b60408051601f19818403018152908290526137e89291602001614e9a565b6040516020818303038152906040528051906020012061380b836000015161312b565b8360200151846040015185606001518660800151805190602001208760a00151805190602001208860c001518960e00151805190602001208a6101000151604051602001612f1f9a99989796959493929190998a5260208a01989098526001600160a01b0396871660408a01526060890195909552608088019390935260a087019190915260c0860152821660e0850152610100840152166101208201526101400190565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612f1f565b6000806000806138fa85613a89565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015613955573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600060405160200161397b90614c3a565b604051602081830303815290604052805190602001204683602001518460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e61018001518f6101a001516040516020016136689e9d9c9b9a999897969594939291906153bf565b6001600160a01b038084166000908152600e6020908152604080832093861683529290522054613a27908290614625565b6001600160a01b039384166000908152600e6020908152604080832095909616825293909352929091209190915550565b6001600160a01b038084166000908152600e6020908152604080832093861683529290522054613a279082906140b3565b60008060008351604114613adf5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401611f84565b50505060208101516040820151606090920151909260009190911a90565b508054613b0990614040565b6000825580601f10613b19575050565b601f01602090049060005260206000209081019061172c91905b80821115613b475760008155600101613b33565b5090565b600060208284031215613b5d57600080fd5b5035919050565b80356001600160a01b0381168114613b7b57600080fd5b919050565b60008060408385031215613b9357600080fd5b613b9c83613b64565b9150613baa60208401613b64565b90509250929050565b600060208284031215613bc557600080fd5b613bce82613b64565b9392505050565b60008060408385031215613be857600080fd5b613bf183613b64565b946020939093013593505050565b600080600060608486031215613c1457600080fd5b613c1d84613b64565b9250613c2b60208501613b64565b9150604084013590509250925092565b600080600060608486031215613c5057600080fd5b613c5984613b64565b9250613c6760208501613b64565b9150613c7560408501613b64565b90509250925092565b60008083601f840112613c9057600080fd5b5081356001600160401b03811115613ca757600080fd5b6020830191508360208260051b8501011115613cc257600080fd5b9250929050565b803563ffffffff81168114613b7b57600080fd5b600080600080600060808688031215613cf557600080fd5b85356001600160401b03811115613d0b57600080fd5b613d1788828901613c7e565b90965094505060208601359250613d3060408701613cc9565b9150613d3e60608701613cc9565b90509295509295909350565b60005b83811015613d65578181015183820152602001613d4d565b50506000910152565b60008151808452613d86816020860160208601613d4a565b601f01601f19169290920160200192915050565b602081528151602082015260006020830151613dc160408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b038116608084015250608083015163ffffffff811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100613e44818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101808085015290506131236101a0840182613d6e565b60008083601f840112613e9757600080fd5b5081356001600160401b03811115613eae57600080fd5b602083019150836020828501011115613cc257600080fd5b60008060008060408587031215613edc57600080fd5b84356001600160401b0380821115613ef357600080fd5b613eff88838901613c7e565b90965094506020870135915080821115613f1857600080fd5b50613f2587828801613e85565b95989497509550505050565b600080600060608486031215613f4657600080fd5b613f4f84613b64565b925060208401359150613c7560408501613b64565b60008060208385031215613f7757600080fd5b82356001600160401b03811115613f8d57600080fd5b613f9985828601613e85565b90969095509350505050565b60008060208385031215613fb857600080fd5b82356001600160401b03811115613fce57600080fd5b613f9985828601613c7e565b60008060008060608587031215613ff057600080fd5b613ff985613b64565b935060208501356001600160401b038082111561401557600080fd5b90860190610240828903121561402a57600080fd5b90935060408601359080821115613f1857600080fd5b600181811c9082168061405457607f821691505b60208210810361407457634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b0393841681526020810192909252909116604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610cde57610cde61409d565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b81835260006001600160fb1b0383111561410b57600080fd5b8260051b80836020870137939093016020019392505050565b600081518084526020808501945080840160005b8381101561415457815187529582019590820190600101614138565b509495945050505050565b6060815260006141736060830186886140f2565b82810360208401526141858186614124565b905082810360408401526141998185614124565b979650505050505050565b600063ffffffff808816835280871660208401525060ff8516604083015283606083015260a0608083015261419960a0830184613d6e565b6080815260006141f06080830187896140f2565b60ff959095166020830152506001600160a01b0392909216604083015260609091015292915050565b6000823561011e1983360301811261423057600080fd5b9190910192915050565b6000823561023e1983360301811261423057600080fd5b6000808335601e1984360301811261426857600080fd5b8301803591506001600160401b0382111561428257600080fd5b602001915036819003821315613cc257600080fd5b60405160a081016001600160401b03811182821017156142b9576142b96140c6565b60405290565b6040516101c081016001600160401b03811182821017156142b9576142b96140c6565b60405161012081016001600160401b03811182821017156142b9576142b96140c6565b60405160c081016001600160401b03811182821017156142b9576142b96140c6565b604051601f8201601f191681016001600160401b038111828210171561434f5761434f6140c6565b604052919050565b600082601f83011261436857600080fd5b81356001600160401b03811115614381576143816140c6565b614394601f8201601f1916602001614327565b8181528460208386010111156143a957600080fd5b816020850160208301376000918101602001919091529392505050565b60008183036102408112156143da57600080fd5b6143e2614297565b91506101c0808212156143f457600080fd5b6143fc6142bf565b91508335825260208401356020830152604084013560408301526060840135606083015261442c60808501613b64565b608083015261443d60a08501613b64565b60a083015261444e60c08501613b64565b60c083015261445f60e08501613b64565b60e0830152610100614472818601613cc9565b90830152610120614484858201613b64565b9083015261014084810135908301526101606144a1818601613b64565b9083015261018084810135908301526101a080850135908301528183526144c9818501613b64565b602084015250506101e0820135604082015261020082013560608201526102208201356001600160401b0381111561450057600080fd5b61450c84828501614357565b60808301525092915050565b6000610120828403121561452b57600080fd5b6145336142e2565b905081356001600160401b038082111561454c57600080fd5b614558858386016143c6565b835261456660208501613b64565b60208401526040840135604084015260608401356060840152608084013591508082111561459357600080fd5b61459f85838601614357565b608084015260a08401359150808211156145b857600080fd5b6145c485838601614357565b60a08401526145d560c08501613b64565b60c084015260e08401359150808211156145ee57600080fd5b506145fb84828501614357565b60e08301525061010061460f818401613b64565b9082015292915050565b6000610cde3683614518565b81810381811115610cde57610cde61409d565b6000823560be1983360301811261423057600080fd5b600060c0823603121561466057600080fd5b614668614305565b82356001600160401b038082111561467f57600080fd5b61468b368387016143c6565b835261469960208601613b64565b6020840152604085013560408401526060850135606084015260808501359150808211156146c657600080fd5b506146d336828601614357565b60808301525060a092830135928101929092525090565b6000610240825180518552602081015160208601526040810151604086015260608101516060860152608081015161472d60808701826001600160a01b03169052565b5060a081015161474860a08701826001600160a01b03169052565b5060c081015161476360c08701826001600160a01b03169052565b5060e081015161477e60e08701826001600160a01b03169052565b506101008181015163ffffffff1690860152610120808201516001600160a01b039081169187019190915261014080830151908701526101608083015182169087015261018080830151908701526101a091820151918601919091526020840151166101c085015260408301516101e085015260608301516102008501526080830151610220850182905261481582860182613d6e565b95945050505050565b6000815160c0845261483360c08501826146ea565b905060018060a01b0360208401511660208501526040830151604085015260608301516060850152608083015184820360808601526148728282613d6e565b91505060a083015160a08501528091505092915050565b8381526060602082015260006148a2606083018561481e565b905060018060a01b0383166040830152949350505050565b602081526000613bce602083018461481e565b60ff841681526001600160a01b038316602082015260606040820181905260009061481590830184613d6e565b60006001820161490c5761490c61409d565b5060010190565b6000610cde36836143c6565b6000808335601e1984360301811261493657600080fd5b83016020810192503590506001600160401b0381111561495557600080fd5b803603821315613cc257600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152833560408201526020840135606082015260408401356080820152606084013560a082015260006149c460808601613b64565b6001600160a01b031660c08301526149de60a08601613b64565b6001600160a01b031660e08301526149f860c08601613b64565b610100614a0f818501836001600160a01b03169052565b614a1b60e08801613b64565b9150610120614a34818601846001600160a01b03169052565b614a3f828901613cc9565b92506101409150614a578286018463ffffffff169052565b614a62818901613b64565b925050610160614a7c818601846001600160a01b03169052565b61018092508188013583860152614a94818901613b64565b9150506101a0614aae818601836001600160a01b03169052565b6101c0915082880135828601526101e09250808801358386015250614ad4818801613b64565b9050610200614aed818601836001600160a01b03169052565b610220915082880135828601526102409250808801358386015250614b148188018861491f565b915082610260860152614b2c61028086018383614964565b925050508281036020840152614b43818587614964565b9695505050505050565b8082028115828204841417610cde57610cde61409d565b600082614b8157634e487b7160e01b600052601260045260246000fd5b500490565b60006001600160401b03821115614b9f57614b9f6140c6565b5060051b60200190565b6000614bbc614bb784614b86565b614327565b80848252602080830192508560051b850136811115614bda57600080fd5b855b81811015614c155780356001600160401b03811115614bfb5760008081fd5b614c0736828a01614518565b865250938201938201614bdc565b50919695505050505050565b600060208284031215614c3357600080fd5b5051919050565b6c084c2e6d2c6a4cae2eacae6e85609b1b8152751d5a5b9d0c8d4d881bdc9a59da5b90da185a5b92590b60521b600d8201527f75696e743235362064657374696e6174696f6e436861696e49642c00000000006023820152701d5a5b9d0c8d4d88191958591b1a5b994b607a1b603e8201526d1d5a5b9d0c8d4d881b9bdb98d94b60921b604f8201526e1859191c995cdcc81cd95b99195c8b608a1b605d820152701859191c995cdcc81c9958d95a5d995c8b607a1b606c820152701859191c995cdcc819195b1959d85d194b607a1b607d820152751859191c995cdcc8189d5b99d95951d85d195dd85e4b60521b608e820152741d5a5b9d0ccc881cddda5d18da189bd85c9912590b605a1b60a4820152721859191c995cdcc81a5b9c1d5d151bdad95b8b606a1b60b9820152731d5a5b9d0c8d4d881a5b9c1d5d105b5bdd5b9d0b60621b60cc820152731859191c995cdcc81bdd5d1c1d5d151bdad95b8b60621b60e08201527f75696e74323536206d696e4f7574707574416d6f756e742c75696e743235362060f48201526c72656675656c416d6f756e742960981b61011482015260006101218201610cde565b670a4cae2eacae6e8560c31b81527510985cda58d4995c5d595cdd0818985cda58d4995c4b60521b60088201527f6164647265737320737761704f7574707574546f6b656e2c0000000000000000601e820152751d5a5b9d0c8d4d881b5a5b94ddd85c13dd5d1c1d5d0b60521b603682015270189e5d195ccccc881b595d1859185d184b607a1b604c82015273627974657320616666696c69617465466565732960601b605d82015260710190565b60008351614eac818460208801613d4a565b835190830190614ec0818360208801613d4a565b01949350505050565b6f52657175657374207769746e6573732960801b815260008351614ef4816010850160208801613d4a565b835190830190614f0b816010840160208801613d4a565b01601001949350505050565b6000610140614f3a838a5180516001600160a01b03168252602090810151910152565b6020890151604084015260408901516060840152614f6e608084018980516001600160a01b03168252602090810151910152565b6001600160a01b03871660c084015260e083018690526101008301819052614f9881840186613d6e565b9050828103610120840152614fad8185613d6e565b9998505050505050505050565b6001600160a01b0385811682526020820185905283166040820152608060608201819052600090614b4390830184613d6e565b60006101208251818552615003828601826146ea565b915050602083015161502060208601826001600160a01b03169052565b5060408301516040850152606083015160608501526080830151848203608086015261504c8282613d6e565b91505060a083015184820360a08601526150668282613d6e565b91505060c083015161508360c08601826001600160a01b03169052565b5060e083015184820360e086015261509b8282613d6e565b915050610100808401516150b9828701826001600160a01b03169052565b5090949350505050565b8781526001600160a01b03878116602083015260408201879052606082018690528481166080830152831660a082015260e060c08201819052600090614fad90830184614fed565b601f821115610def57600081815260208120601f850160051c810160208610156151325750805b601f850160051c820191505b8181101561184b5782815560010161513e565b81516001600160401b0381111561516a5761516a6140c6565b61517e816151788454614040565b8461510b565b602080601f8311600181146151b3576000841561519b5750858301515b600019600386901b1c1916600185901b17855561184b565b600085815260208120601f198616915b828110156151e2578886015182559484019460019091019084016151c3565b50858210156152005787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000613bce6020830184614fed565b6001600160e01b0319813581811691600485101561524b5780818660040360031b1b83161692505b505092915050565b6000808585111561526357600080fd5b8386111561527057600080fd5b5050820193919092039150565b600082601f83011261528e57600080fd5b8135602061529e614bb783614b86565b82815260059290921b840181019181810190868411156152bd57600080fd5b8286015b848110156152d857803583529183019183016152c1565b509695505050505050565b6000806000606084860312156152f857600080fd5b83356001600160401b038082111561530f57600080fd5b818601915086601f83011261532357600080fd5b81356020615333614bb783614b86565b82815260059290921b8401810191818101908a84111561535257600080fd5b948201945b8386101561537057853582529482019490820190615357565b9750508701359250508082111561538657600080fd5b6153928783880161527d565b935060408601359150808211156153a857600080fd5b506153b58682870161527d565b9150509250925092565b8e8152602081018e9052604081018d9052606081018c90526001600160a01b038b811660808301528a811660a083015289811660c0830152881660e08201526101c0810163ffffffff88166101008301526001600160a01b0387166101208301528561014083015261543d6101608301866001600160a01b03169052565b6101808201939093526101a001529c9b505050505050505050505050565b82815260008251615473816020850160208701613d4a565b91909101602001939250505056fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a264697066735822122054cdd9723bc8d508b017a4b2e78f41d7a759e6d74bd3b9fe19ec9c1968802c2e64736f6c63430008130033000000000000000000000000a5acba07788f16b4790fcbb09ca3b7fc8dd053a2000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Deployed Bytecode
0x6080604052600436106102675760003560e01c8063733957f811610144578063a42dce80116100b6578063d9e9a7be1161007a578063d9e9a7be146107cb578063df2ebdbb146107de578063e1282c5c14610806578063e9899ed21461084a578063f36ba4d81461086a578063f82814861461088a57600080fd5b8063a42dce801461074f578063ae3100c01461076f578063b746078a14610785578063cc6dc63a14610798578063cf376c1d146107b857600080fd5b80637f660b01116101085780637f660b011461068457806380f7013e146106a4578063823d0088146106dc5780638da5cb5b146106f1578063967aef081461070f5780639ed0cb131461072f57600080fd5b8063733957f8146105c15780637373161f146105e157806374f8d3fd1461060157806376479d1b14610644578063795d86b81461066457600080fd5b80633af32abf116101dd5780634c7a7732116101a15780634c7a7732146104d05780635b94db27146104fd5780636a0706db1461051d5780636a7372da1461053d5780636afdd8501461056d57806370b55089146105a157600080fd5b80633af32abf146104135780633bd1adec146104435780633cbc7eaa146104585780633cf3c2b61461047f5780633de408a11461049257600080fd5b806312f07c251161022f57806312f07c25146103395780631e789c361461035957806320798eb7146103a257806320f99c0a146103b557806320ff430b146103d357806331feeadd146103f357600080fd5b8063091b89461461026c5780630b3458791461028e5780630c0a0ccb146102cb5780630cb352e0146102f95780630e4bfd6e14610319575b600080fd5b34801561027857600080fd5b5061028c610287366004613b4b565b6108aa565b005b34801561029a57600080fd5b506004546102ae906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102d757600080fd5b506102eb6102e6366004613b80565b610cb7565b6040519081526020016102c2565b34801561030557600080fd5b506005546102ae906001600160a01b031681565b34801561032557600080fd5b506003546102ae906001600160a01b031681565b34801561034557600080fd5b506002546102ae906001600160a01b031681565b34801561036557600080fd5b50610392610374366004613bb3565b6001600160a01b03166000908152600c602052604090205460ff1690565b60405190151581526020016102c2565b61028c6103b0366004613bd5565b610ce4565b3480156103c157600080fd5b506001546001600160a01b03166102ae565b3480156103df57600080fd5b5061028c6103ee366004613bff565b610e14565b3480156103ff57600080fd5b5061028c61040e366004613c3b565b610e4a565b34801561041f57600080fd5b5061039261042e366004613bb3565b600d6020526000908152604090205460ff1681565b34801561044f57600080fd5b5061028c610f13565b34801561046457600080fd5b5061046d600181565b60405160ff90911681526020016102c2565b61028c61048d366004613cdd565b610f49565b34801561049e57600080fd5b506102eb6104ad366004613c3b565b601060209081526000938452604080852082529284528284209052825290205481565b3480156104dc57600080fd5b506104f06104eb366004613b4b565b611195565b6040516102c29190613d9a565b34801561050957600080fd5b5061028c610518366004613bb3565b61133f565b34801561052957600080fd5b5061028c610538366004613bb3565b6113b4565b34801561054957600080fd5b50610392610558366004613b4b565b600f6020526000908152604090205460ff1681565b34801561057957600080fd5b506102ae7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b3480156105ad57600080fd5b5061028c6105bc366004613ec6565b611401565b3480156105cd57600080fd5b5061028c6105dc366004613bb3565b6115e4565b3480156105ed57600080fd5b5061028c6105fc366004613b4b565b611631565b34801561060d57600080fd5b506102ae61061c366004613bd5565b6001600160a01b039182166000908152600b6020908152604080832093835292905220541690565b34801561065057600080fd5b5061028c61065f366004613bb3565b611661565b34801561067057600080fd5b5061028c61067f366004613bb3565b61172f565b34801561069057600080fd5b506006546102ae906001600160a01b031681565b3480156106b057600080fd5b506102eb6106bf366004613b80565b600e60209081526000928352604080842090915290825290205481565b3480156106e857600080fd5b5061046d600281565b3480156106fd57600080fd5b506000546001600160a01b03166102ae565b34801561071b57600080fd5b5061028c61072a366004613bd5565b61179d565b34801561073b57600080fd5b5061028c61074a366004613f31565b611853565b34801561075b57600080fd5b5061028c61076a366004613bb3565b6118bb565b34801561077b57600080fd5b506102eb60085481565b61028c610793366004613f64565b611908565b3480156107a457600080fd5b5061028c6107b3366004613bb3565b61193d565b61028c6107c6366004613fa5565b61198a565b61028c6107d9366004613fda565b611bef565b3480156107ea57600080fd5b506102ae73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561081257600080fd5b50610826610821366004613b4b565b611d5d565b604080518251815260208084015190820152918101511515908201526060016102c2565b34801561085657600080fd5b5061028c610865366004613bb3565b611dc1565b34801561087657600080fd5b5061028c610885366004613bb3565b611e0e565b34801561089657600080fd5b506007546102ae906001600160a01b031681565b6000818152600a602081815260408084208151610180810183528154815260018201546001600160a01b0390811694820194909452600282015484169281019290925260038101548084166060840152600160a01b900463ffffffff1660808301526004810154831660a08301526005810154831660c0830152600681015490921660e082015260078201546101008201526008820154610120820152600982015461014082015291810180546101608401919061096790614040565b80601f016020809104026020016040519081016040528092919081815260200182805461099390614040565b80156109e05780601f106109b5576101008083540402835291602001916109e0565b820191906000526020600020905b8154815290600101906020018083116109c357829003601f168201915b5050509190925250505060408101519091506001600160a01b0316610a18576040516341abc80160e01b815260040160405180910390fd5b8051421015610a3a57604051630888f67560e41b815260040160405180910390fd5b6020808201516001600160a01b03166000908152600d909152604090205460ff1615610b56576000610a76826101000151836101600151611e5b565b6006546040848101519051632ad7b7d360e11b8152600481018790526001600160a01b03918216602482015292935016906355af6fa690604401600060405180830381600087803b158015610aca57600080fd5b505af1158015610ade573d6000803e3d6000fd5b5050505081602001516001600160a01b03166362524dd78360a001518385604001516040518463ffffffff1660e01b8152600401610b1e9392919061407a565b600060405180830381600087803b158015610b3857600080fd5b505af1158015610b4c573d6000803e3d6000fd5b5050505050610bcb565b60075460a08201516101008301516040808501519051632385922d60e01b81526001600160a01b0390941693632385922d93610b98939092909160040161407a565b600060405180830381600087803b158015610bb257600080fd5b505af1158015610bc6573d6000803e3d6000fd5b505050505b817f5785ffbb8ccb1fbfff4aaf0bf7419c43517c350880dabf3644dfd1d05f1186938260a001518361010001518460400151604051610c0c9392919061407a565b60405180910390a26000828152600f60209081526040808320805460ff19166001908117909155600a9283905290832083815590810180546001600160a01b0319908116909155600282018054821690556003820180546001600160c01b0319169055600482018054821690556005820180548216905560068201805490911690556007810183905560088101839055600981018390559190610cb190830182613afd565b50505050565b6001600160a01b038083166000908152600e60209081526040808320938516835292905220545b92915050565b336000908152600e602090815260408083206001600160a01b0386168452909152902054610d139082906140b3565b336000908152600e602090815260408083206001600160a01b03871680855292529091209190915573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed1901610df457803414610d7657604051634eba4d4960e11b815260040160405180910390fd5b6007546040516000916001600160a01b03169061138890849084818181858888f193505050503d8060008114610dc8576040519150601f19603f3d011682016040523d82523d6000602084013e610dcd565b606091505b5050905080610def576040516312171d8360e31b815260040160405180910390fd5b505050565b600754610e10906001600160a01b038481169133911684611ef3565b5050565b6000546001600160a01b03163314610e3f57604051635fc483c560e01b815260040160405180910390fd5b610def838284611f8d565b6001600160a01b03808416600090815260106020908152604080832086851684528252808320938516835292905220548015610cb1576001600160a01b03808516600090815260106020908152604080832087851680855290835281842094871684529390915280822091909155516362524dd760e01b81526362524dd790610edb9085908590899060040161407a565b600060405180830381600087803b158015610ef557600080fd5b505af1158015610f09573d6000803e3d6000fd5b5050505050505050565b6001546001600160a01b03163314610f3e57604051637c91ccdd60e01b815260040160405180910390fd5b610f473361203f565b565b6000846001600160401b03811115610f6357610f636140c6565b604051908082528060200260200182016040528015610f8c578160200160208202803683370190505b5090506000856001600160401b03811115610fa957610fa96140c6565b604051908082528060200260200182016040528015610fd2578160200160208202803683370190505b50905060005b868110156110a9576000600960008a8a85818110610ff857610ff86140dc565b602090810292909201358352508181019290925260409081016000208151606081018352815481526001820154938101939093526002015460ff16151590820181905290915061105b5760405163a4d9007d60e01b815260040160405180910390fd5b8060000151848381518110611072576110726140dc565b6020026020010181815250508060200151838381518110611095576110956140dc565b602090810291909101015250600101610fd8565b50600360009054906101000a90046001600160a01b03166001600160a01b0316635813c9c534868660018a8d8d8a8a6040516020016110eb949392919061415f565b6040516020818303038152906040526040518763ffffffff1660e01b815260040161111a9594939291906141a4565b6000604051808303818588803b15801561113357600080fd5b505af1158015611147573d6000803e3d6000fd5b50505050507f3e09b55b6efb54718ae4486c6229eaf5afca42c1aed76e189d9cfaeb3b539f4e8787600133346040516111849594939291906141dc565b60405180910390a150505050505050565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101919091526000828152600a60208181526040928390208351610180810185528154815260018201546001600160a01b0390811693820193909352600282015483169481019490945260038101548083166060860152600160a01b900463ffffffff1660808501526004810154821660a08501526005810154821660c0850152600681015490911660e08401526007810154610100840152600881015461012084015260098101546101408401529081018054610160840191906112b690614040565b80601f01602080910402602001604051908101604052809291908181526020018280546112e290614040565b801561132f5780601f106113045761010080835404028352916020019161132f565b820191906000526020600020905b81548152906001019060200180831161131257829003601f168201915b5050505050815250509050919050565b6000546001600160a01b0316331461136a57604051635fc483c560e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b6000546001600160a01b031633146113df57604051635fc483c560e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b611442848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061209292505050565b60005b838110156115dd5784848281811061145f5761145f6140dc565b90506020028101906114719190614219565b61147b908061423a565b6101800135858583818110611492576114926140dc565b90506020028101906114a49190614219565b60400135108061150c57508484828181106114c1576114c16140dc565b90506020028101906114d39190614219565b6114dd908061423a565b6101a001358585838181106114f4576114f46140dc565b90506020028101906115069190614219565b60600135105b1561152a5760405163308657c360e21b815260040160405180910390fd5b600085858381811061153e5761153e6140dc565b90506020028101906115509190614219565b61155e9060a0810190614251565b905011156115a05761159b85858381811061157b5761157b6140dc565b905060200281019061158d9190614219565b61159690614619565b6120e5565b6115d5565b6115d58585838181106115b5576115b56140dc565b90506020028101906115c79190614219565b6115d090614619565b61282d565b600101611445565b5050505050565b6000546001600160a01b0316331461160f57604051635fc483c560e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461165c57604051635fc483c560e01b815260040160405180910390fd5b600855565b6000546001600160a01b0316331461168c57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600d602052604090205460ff16156116c65760405163406c5bd360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff161561170057604051633ba24ff960e11b815260040160405180910390fd5b6001600160a01b0381166000908152600d60205260409020805460ff1916600117905561172c81612d86565b50565b6000546001600160a01b0316331461175a57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604090205460ff161561179457604051633ba24ff960e11b815260040160405180910390fd5b61172c81612d86565b336000908152600e602090815260408083206001600160a01b03861684529091529020546117cc908290614625565b336000818152600e602090815260408083206001600160a01b038881168552925291829020939093556007549051632385922d60e01b8152921691632385922d9161181d918691869160040161407a565b600060405180830381600087803b15801561183757600080fd5b505af115801561184b573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461187e57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b039081166000908152600b60209081526040808320948352939052919091208054919092166001600160a01b0319909116179055565b6000546001600160a01b031633146118e657604051635fc483c560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b0316331461193357604051631bd147a760e01b815260040160405180910390fd5b610e108282612daa565b6000546001600160a01b0316331461196857604051635fc483c560e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b82811015611bcd5760008484838181106119aa576119aa6140dc565b90506020028101906119bc9190614638565b6119c59061464e565b905060006119d68260000151612e53565b60008181526009602052604090206002015490915060ff1615611a0c5760405163234bc0ff60e21b815260040160405180910390fd5b611a3282602001516001600160a01b03166000908152600c602052604090205460ff1690565b611a4f576040516315812c6160e11b815260040160405180910390fd5b815151610180015160408301511080611a7257508151516101a001516060830151105b15611a905760405163308657c360e21b815260040160405180910390fd5b81602001516001600160a01b031663da2de3448360a001518385336040518563ffffffff1660e01b8152600401611ac993929190614889565b6000604051808303818588803b158015611ae257600080fd5b505af1158015611af6573d6000803e3d6000fd5b50505050508160a0015184611b0b91906140b3565b6040805160608082018352858301518252850151602080830191825260018385018181526000888152600984528690209451855592518482015591516002909301805460ff191693151593909317909255915192965083927fd83e4fbd120e768f3bb813ecfa1a2b16c323fa7dfa07db1cd6434b3cbc97bc7592913391611b94918891016148ba565b60408051601f1981840301815290829052611bb09392916148cd565b60405180910390a250508080611bc5906148fa565b91505061198e565b5080341015610def57604051637bf261fb60e01b815260040160405180910390fd5b6000611c02611bfd85614913565b612e53565b9050611c1460e0850160c08601613bb3565b6001600160a01b0316336001600160a01b031614611c4557604051631db3b85960e01b815260040160405180910390fd5b60008181526009602052604090206002015460ff1615611c785760405163234bc0ff60e21b815260040160405180910390fd5b604080516060810182526000808252602080830182815260018486018181528785526009845286852095518655915190850155516002909301805460ff1916931515939093179092556001600160a01b0388168152600c909152205460ff16611cf4576040516315812c6160e11b815260040160405180910390fd5b604051632757107160e11b81526001600160a01b03861690634eae20e290611d249087908790879060040161498d565b600060405180830381600087803b158015611d3e57600080fd5b505af1158015611d52573d6000803e3d6000fd5b505050505050505050565b611d83604051806060016040528060008152602001600081526020016000151581525090565b506000908152600960209081526040918290208251606081018452815481526001820154928101929092526002015460ff1615159181019190915290565b6000546001600160a01b03163314611dec57604051635fc483c560e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314611e3957604051635fc483c560e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008084511115611eea5760008451601a14611e8d57604051634115207f60e01b815260040160405180910390fd5b611e98856014612f3c565b9050611ea5856000612f99565b925065ffffffffffff811615611ee857662386f26fc10000611ecf65ffffffffffff831688614b4d565b611ed99190614b64565b9150611ee58287614625565b95505b505b50929392505050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806115dd5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161202b576000816001600160a01b03168361138890604051600060405180830381858888f193505050503d8060008114612004576040519150601f19603f3d011682016040523d82523d6000602084013e612009565b606091505b5050905080610cb1576040516312171d8360e31b815260040160405180910390fd5b610def6001600160a01b0384168284612ffe565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60006120a66120a18486614ba9565b61307f565b905060006120b4828461310b565b6002549091506001600160a01b038083169116146115dd57604051633c6ae50160e11b815260040160405180910390fd5b60006120f4826000015161312b565b8251602001519091506001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1460008161219e578351602090810151908501516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015612175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121999190614c21565b6121ae565b83602001516001600160a01b0316315b84515161012081015161014082015160608301516040909301519394506001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3169363137c29fe9361220793929161319b565b8651516101400151600454604080518082018252600080825260209182015281518083019092526001600160a01b0390921681529081019190915287515160800151604051889061225a90602001614c3a565b60405160208183030381529060405260405160200161227890614deb565b60408051601f19818403018152908290526122969291602001614e9a565b60408051601f1981840301815260608301909152602e80835290919061548260208301396040516020016122cb929190614ec9565b6040516020818303038152906040528a60e001516040518763ffffffff1660e01b815260040161230096959493929190614f17565b600060405180830381600087803b15801561231a57600080fd5b505af115801561232e573d6000803e3d6000fd5b5050600480548751516101208101516101409091015160c08a015160a08b015160405163017c1d7560e31b81526001600160a01b039095169750630be0eba8965061238195939492939192909101614fba565b600060405180830381600087803b15801561239b57600080fd5b505af11580156123af573d6000803e3d6000fd5b50505050600082612443578451602090810151908601516040516370a0823160e01b81526001600160a01b039182166004820152849291909116906370a0823190602401602060405180830381865afa158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614c21565b61243e9190614625565b61245d565b8185602001516001600160a01b03163161245d9190614625565b85516040015190915081101561248657604051633453a1e760e01b815260040160405180910390fd5b6020808601516001600160a01b03166000908152600d909152604090205460ff166124bd576124bd818660000151602001516131fd565b6000600854426124cd91906140b3565b60208088015188518201516001600160a01b039182166000818152600b855260408082208d51518701518352909552849020546006549451633ed33c7f60e01b81529596509094633ed33c7f94612538948994938d938a939183169291909116908f906004016150c3565b600060405180830381600087803b15801561255257600080fd5b505af1158015612566573d6000803e3d6000fd5b5050505060405180610180016040528082815260200187602001516001600160a01b03168152602001876000015160000151608001516001600160a01b0316815260200187600001516000015160c001516001600160a01b03168152602001876000015160000151610100015163ffffffff1681526020018760000151602001516001600160a01b03168152602001336001600160a01b031681526020018761010001516001600160a01b031681526020018381526020018760400151815260200187606001518152602001876000015160800151815250600a60008781526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061010082015181600701556101208201518160080155610140820151816009015561016082015181600a0190816127c79190615151565b50905050847f14a241d5b404d2061ceb9a847972acfd690983f1d8a0fef9779b8191aa1b7ef2600133896040516020016128019190615210565b60408051601f198184030181529082905261281d9392916148cd565b60405180910390a2505050505050565b6020808201516001600160a01b03166000908152600d909152604090205460ff1661286c578051516101408101516101209091015161286c91906131fd565b600061287b826000015161312b565b82515161012081015161014082015160608301516040909301519394506001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3169363137c29fe936128d493929161319b565b845151610140015160208087015160408051808201825260008082529084015280518082019091526001600160a01b0390911681529081019190915285515160800151604051869061292890602001614c3a565b60405160208183030381529060405260405160200161294690614deb565b60408051601f19818403018152908290526129649291602001614e9a565b60408051601f1981840301815260608301909152602e8083529091906154826020830139604051602001612999929190614ec9565b6040516020818303038152906040528860e001516040518763ffffffff1660e01b81526004016129ce96959493929190614f17565b600060405180830381600087803b1580156129e857600080fd5b505af11580156129fc573d6000803e3d6000fd5b50505050600060085442612a1091906140b3565b602080850151855151610140810151610120909101516001600160a01b039283166000818152600b865260408082208b51518801518352909652859020546006549551633ed33c7f60e01b81529697509095633ed33c7f95612a82958a938a9390821692909116908c906004016150c3565b600060405180830381600087803b158015612a9c57600080fd5b505af1158015612ab0573d6000803e3d6000fd5b5050505060405180610180016040528082815260200184602001516001600160a01b03168152602001846000015160000151608001516001600160a01b0316815260200184600001516000015160c001516001600160a01b03168152602001846000015160000151610100015163ffffffff16815260200184600001516000015161012001516001600160a01b03168152602001336001600160a01b031681526020018461010001516001600160a01b03168152602001846000015160000151610140015181526020018460400151815260200184606001518152602001846000015160800151815250600a60008481526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061010082015181600701556101208201518160080155610140820151816009015561016082015181600a019081612d239190615151565b50905050817f14a241d5b404d2061ceb9a847972acfd690983f1d8a0fef9779b8191aa1b7ef260013386604051602001612d5d9190615210565b60408051601f1981840301815290829052612d799392916148cd565b60405180910390a2505050565b6001600160a01b03166000908152600c60205260409020805460ff19166001179055565b6000612db68284615223565b60e01c905060008080612dcc8560048189615253565b810190612dd991906152e3565b92509250925060005b8351811015612e4a57612e4285858381518110612e0157612e016140dc565b6020026020010151858481518110612e1b57612e1b6140dc565b6020026020010151858581518110612e3557612e356140dc565b6020026020010151613232565b600101612de2565b50505050505050565b6000604051602001612e6490614deb565b604051602081830303815290604052604051602001612e8290614c3a565b60408051601f1981840301815290829052612ea09291602001614e9a565b60405160208183030381529060405280519060200120612ec383600001516135dc565b836020015184604001518560600151866080015180519060200120604051602001612f1f9695949392919095865260208601949094526001600160a01b039290921660408501526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b6000612f498260066140b3565b83511015612f905760405162461bcd60e51b8152602060048201526014602482015273746f55696e7434385f6f75744f66426f756e647360601b6044820152606401611f84565b50016006015190565b6000612fa68260146140b3565b83511015612fee5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401611f84565b500160200151600160601b900490565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610cb15760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611f84565b60007f0229eabb7e69af818c010d3333cd777014bff2c06ac717d3e0df036a6e9ff570815b835181101561310457816130d08583815181106130c3576130c36140dc565b6020026020010151613686565b60408051602081019390935282015260600160408051601f19818403018152919052805160209091012091506001016130a4565b5092915050565b600080613117846138b0565b905061312381846138eb565b949350505050565b600060405160200161313c90614deb565b60405160208183030381529060405260405160200161315a90614c3a565b60408051601f19818403018152908290526131789291602001614e9a565b60405160208183030381529060405280519060200120612ec3836000015161396a565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a0810182526001600160a01b039590951660608601908152608086019490945292845260208401919091529082015290565b816132083383610cb7565b101561322757604051632e77ac1d60e11b815260040160405180910390fd5b610e103382846139f6565b6000838152600a602081815260408084208151610180810183528154815260018201546001600160a01b0390811694820194909452600282015484169281019290925260038101548084166060840152600160a01b900463ffffffff1660808301526004810154831660a08301526005810154831660c0830152600681015490921660e08201526007820154610100820152600882015461012082015260098201546101408201529181018054610160840191906132ef90614040565b80601f016020809104026020016040519081016040528092919081815260200182805461331b90614040565b80156133685780601f1061333d57610100808354040283529160200191613368565b820191906000526020600020905b81548152906001019060200180831161334b57829003601f168201915b5050509190925250505060408101519091506001600160a01b03166133a0576040516341abc80160e01b815260040160405180910390fd5b8463ffffffff16816080015163ffffffff16146133d05760405163f63c9e4d60e01b815260040160405180910390fd5b8281610120015111806133e7575081816101400151115b15613405576040516330be5d5d60e11b815260040160405180910390fd5b600061341b826101000151836101600151611e5b565b6020808401516001600160a01b03166000908152600d909152604090205490915060ff1615613509578082610100015111156134b057600654604051630710376f60e11b8152600481018790526001600160a01b0390911690630e206ede90602401600060405180830381600087803b15801561349757600080fd5b505af11580156134ab573d6000803e3d6000fd5b505050505b60e08201516001600160a01b0390811660009081526010602090815260408083208287015185168452825280832060a0870151909416835292905290812080548392906134fe9084906140b3565b909155506135219050565b6135218260c001518360a00151846101000151613a58565b6000858152600a6020819052604082208281556001810180546001600160a01b0319908116909155600282018054821690556003820180546001600160c01b03191690556004820180548216905560058201805482169055600682018054909116905560078101839055600881018390556009810183905591906135a790830182613afd565b505060405185907f7eea86cc10df3b8a859a99d48d6858b1128a479f035d0223cf9dd929f37c607990600090a2505050505050565b60006040516020016135ed90614c3a565b604051602081830303815290604052805190602001208260000151468460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e61018001518f6101a001516040516020016136689e9d9c9b9a999897969594939291906153bf565b60408051601f1981840301815290829052612f1f929160200161545b565b6040516b08af0e8e4c2c6e88af0cac6560a31b60208201526f14995c5d595cdd081c995c5d595cdd0b60821b602c8201526e1859191c995cdcc81c9bdd5d195c8b608a1b603c8201527f75696e743235362070726f6d69736564416d6f756e742c000000000000000000604b8201527f75696e743235362070726f6d6973656452656675656c416d6f756e742c000000606282015270189e5d195cc81c9bdd5d195c91185d184b607a1b607f82015271189e5d195cc81cddd85c14185e5b1bd8590b60721b6090820152721859191c995cdcc81cddd85c149bdd5d195c8b606a1b60a282015273189e5d195cc81d5cd95c94da59db985d1d5c994b60621b60b582015273616464726573732062656e65666963696172792960601b60c982015260009060dd016040516020818303038152906040526040516020016137ca90614deb565b60408051601f19818403018152908290526137e89291602001614e9a565b6040516020818303038152906040528051906020012061380b836000015161312b565b8360200151846040015185606001518660800151805190602001208760a00151805190602001208860c001518960e00151805190602001208a6101000151604051602001612f1f9a99989796959493929190998a5260208a01989098526001600160a01b0396871660408a01526060890195909552608088019390935260a087019190915260c0860152821660e0850152610100840152166101208201526101400190565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612f1f565b6000806000806138fa85613a89565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015613955573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b600060405160200161397b90614c3a565b604051602081830303815290604052805190602001204683602001518460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e61018001518f6101a001516040516020016136689e9d9c9b9a999897969594939291906153bf565b6001600160a01b038084166000908152600e6020908152604080832093861683529290522054613a27908290614625565b6001600160a01b039384166000908152600e6020908152604080832095909616825293909352929091209190915550565b6001600160a01b038084166000908152600e6020908152604080832093861683529290522054613a279082906140b3565b60008060008351604114613adf5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401611f84565b50505060208101516040820151606090920151909260009190911a90565b508054613b0990614040565b6000825580601f10613b19575050565b601f01602090049060005260206000209081019061172c91905b80821115613b475760008155600101613b33565b5090565b600060208284031215613b5d57600080fd5b5035919050565b80356001600160a01b0381168114613b7b57600080fd5b919050565b60008060408385031215613b9357600080fd5b613b9c83613b64565b9150613baa60208401613b64565b90509250929050565b600060208284031215613bc557600080fd5b613bce82613b64565b9392505050565b60008060408385031215613be857600080fd5b613bf183613b64565b946020939093013593505050565b600080600060608486031215613c1457600080fd5b613c1d84613b64565b9250613c2b60208501613b64565b9150604084013590509250925092565b600080600060608486031215613c5057600080fd5b613c5984613b64565b9250613c6760208501613b64565b9150613c7560408501613b64565b90509250925092565b60008083601f840112613c9057600080fd5b5081356001600160401b03811115613ca757600080fd5b6020830191508360208260051b8501011115613cc257600080fd5b9250929050565b803563ffffffff81168114613b7b57600080fd5b600080600080600060808688031215613cf557600080fd5b85356001600160401b03811115613d0b57600080fd5b613d1788828901613c7e565b90965094505060208601359250613d3060408701613cc9565b9150613d3e60608701613cc9565b90509295509295909350565b60005b83811015613d65578181015183820152602001613d4d565b50506000910152565b60008151808452613d86816020860160208601613d4a565b601f01601f19169290920160200192915050565b602081528151602082015260006020830151613dc160408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b038116608084015250608083015163ffffffff811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100613e44818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101808085015290506131236101a0840182613d6e565b60008083601f840112613e9757600080fd5b5081356001600160401b03811115613eae57600080fd5b602083019150836020828501011115613cc257600080fd5b60008060008060408587031215613edc57600080fd5b84356001600160401b0380821115613ef357600080fd5b613eff88838901613c7e565b90965094506020870135915080821115613f1857600080fd5b50613f2587828801613e85565b95989497509550505050565b600080600060608486031215613f4657600080fd5b613f4f84613b64565b925060208401359150613c7560408501613b64565b60008060208385031215613f7757600080fd5b82356001600160401b03811115613f8d57600080fd5b613f9985828601613e85565b90969095509350505050565b60008060208385031215613fb857600080fd5b82356001600160401b03811115613fce57600080fd5b613f9985828601613c7e565b60008060008060608587031215613ff057600080fd5b613ff985613b64565b935060208501356001600160401b038082111561401557600080fd5b90860190610240828903121561402a57600080fd5b90935060408601359080821115613f1857600080fd5b600181811c9082168061405457607f821691505b60208210810361407457634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b0393841681526020810192909252909116604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610cde57610cde61409d565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b81835260006001600160fb1b0383111561410b57600080fd5b8260051b80836020870137939093016020019392505050565b600081518084526020808501945080840160005b8381101561415457815187529582019590820190600101614138565b509495945050505050565b6060815260006141736060830186886140f2565b82810360208401526141858186614124565b905082810360408401526141998185614124565b979650505050505050565b600063ffffffff808816835280871660208401525060ff8516604083015283606083015260a0608083015261419960a0830184613d6e565b6080815260006141f06080830187896140f2565b60ff959095166020830152506001600160a01b0392909216604083015260609091015292915050565b6000823561011e1983360301811261423057600080fd5b9190910192915050565b6000823561023e1983360301811261423057600080fd5b6000808335601e1984360301811261426857600080fd5b8301803591506001600160401b0382111561428257600080fd5b602001915036819003821315613cc257600080fd5b60405160a081016001600160401b03811182821017156142b9576142b96140c6565b60405290565b6040516101c081016001600160401b03811182821017156142b9576142b96140c6565b60405161012081016001600160401b03811182821017156142b9576142b96140c6565b60405160c081016001600160401b03811182821017156142b9576142b96140c6565b604051601f8201601f191681016001600160401b038111828210171561434f5761434f6140c6565b604052919050565b600082601f83011261436857600080fd5b81356001600160401b03811115614381576143816140c6565b614394601f8201601f1916602001614327565b8181528460208386010111156143a957600080fd5b816020850160208301376000918101602001919091529392505050565b60008183036102408112156143da57600080fd5b6143e2614297565b91506101c0808212156143f457600080fd5b6143fc6142bf565b91508335825260208401356020830152604084013560408301526060840135606083015261442c60808501613b64565b608083015261443d60a08501613b64565b60a083015261444e60c08501613b64565b60c083015261445f60e08501613b64565b60e0830152610100614472818601613cc9565b90830152610120614484858201613b64565b9083015261014084810135908301526101606144a1818601613b64565b9083015261018084810135908301526101a080850135908301528183526144c9818501613b64565b602084015250506101e0820135604082015261020082013560608201526102208201356001600160401b0381111561450057600080fd5b61450c84828501614357565b60808301525092915050565b6000610120828403121561452b57600080fd5b6145336142e2565b905081356001600160401b038082111561454c57600080fd5b614558858386016143c6565b835261456660208501613b64565b60208401526040840135604084015260608401356060840152608084013591508082111561459357600080fd5b61459f85838601614357565b608084015260a08401359150808211156145b857600080fd5b6145c485838601614357565b60a08401526145d560c08501613b64565b60c084015260e08401359150808211156145ee57600080fd5b506145fb84828501614357565b60e08301525061010061460f818401613b64565b9082015292915050565b6000610cde3683614518565b81810381811115610cde57610cde61409d565b6000823560be1983360301811261423057600080fd5b600060c0823603121561466057600080fd5b614668614305565b82356001600160401b038082111561467f57600080fd5b61468b368387016143c6565b835261469960208601613b64565b6020840152604085013560408401526060850135606084015260808501359150808211156146c657600080fd5b506146d336828601614357565b60808301525060a092830135928101929092525090565b6000610240825180518552602081015160208601526040810151604086015260608101516060860152608081015161472d60808701826001600160a01b03169052565b5060a081015161474860a08701826001600160a01b03169052565b5060c081015161476360c08701826001600160a01b03169052565b5060e081015161477e60e08701826001600160a01b03169052565b506101008181015163ffffffff1690860152610120808201516001600160a01b039081169187019190915261014080830151908701526101608083015182169087015261018080830151908701526101a091820151918601919091526020840151166101c085015260408301516101e085015260608301516102008501526080830151610220850182905261481582860182613d6e565b95945050505050565b6000815160c0845261483360c08501826146ea565b905060018060a01b0360208401511660208501526040830151604085015260608301516060850152608083015184820360808601526148728282613d6e565b91505060a083015160a08501528091505092915050565b8381526060602082015260006148a2606083018561481e565b905060018060a01b0383166040830152949350505050565b602081526000613bce602083018461481e565b60ff841681526001600160a01b038316602082015260606040820181905260009061481590830184613d6e565b60006001820161490c5761490c61409d565b5060010190565b6000610cde36836143c6565b6000808335601e1984360301811261493657600080fd5b83016020810192503590506001600160401b0381111561495557600080fd5b803603821315613cc257600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152833560408201526020840135606082015260408401356080820152606084013560a082015260006149c460808601613b64565b6001600160a01b031660c08301526149de60a08601613b64565b6001600160a01b031660e08301526149f860c08601613b64565b610100614a0f818501836001600160a01b03169052565b614a1b60e08801613b64565b9150610120614a34818601846001600160a01b03169052565b614a3f828901613cc9565b92506101409150614a578286018463ffffffff169052565b614a62818901613b64565b925050610160614a7c818601846001600160a01b03169052565b61018092508188013583860152614a94818901613b64565b9150506101a0614aae818601836001600160a01b03169052565b6101c0915082880135828601526101e09250808801358386015250614ad4818801613b64565b9050610200614aed818601836001600160a01b03169052565b610220915082880135828601526102409250808801358386015250614b148188018861491f565b915082610260860152614b2c61028086018383614964565b925050508281036020840152614b43818587614964565b9695505050505050565b8082028115828204841417610cde57610cde61409d565b600082614b8157634e487b7160e01b600052601260045260246000fd5b500490565b60006001600160401b03821115614b9f57614b9f6140c6565b5060051b60200190565b6000614bbc614bb784614b86565b614327565b80848252602080830192508560051b850136811115614bda57600080fd5b855b81811015614c155780356001600160401b03811115614bfb5760008081fd5b614c0736828a01614518565b865250938201938201614bdc565b50919695505050505050565b600060208284031215614c3357600080fd5b5051919050565b6c084c2e6d2c6a4cae2eacae6e85609b1b8152751d5a5b9d0c8d4d881bdc9a59da5b90da185a5b92590b60521b600d8201527f75696e743235362064657374696e6174696f6e436861696e49642c00000000006023820152701d5a5b9d0c8d4d88191958591b1a5b994b607a1b603e8201526d1d5a5b9d0c8d4d881b9bdb98d94b60921b604f8201526e1859191c995cdcc81cd95b99195c8b608a1b605d820152701859191c995cdcc81c9958d95a5d995c8b607a1b606c820152701859191c995cdcc819195b1959d85d194b607a1b607d820152751859191c995cdcc8189d5b99d95951d85d195dd85e4b60521b608e820152741d5a5b9d0ccc881cddda5d18da189bd85c9912590b605a1b60a4820152721859191c995cdcc81a5b9c1d5d151bdad95b8b606a1b60b9820152731d5a5b9d0c8d4d881a5b9c1d5d105b5bdd5b9d0b60621b60cc820152731859191c995cdcc81bdd5d1c1d5d151bdad95b8b60621b60e08201527f75696e74323536206d696e4f7574707574416d6f756e742c75696e743235362060f48201526c72656675656c416d6f756e742960981b61011482015260006101218201610cde565b670a4cae2eacae6e8560c31b81527510985cda58d4995c5d595cdd0818985cda58d4995c4b60521b60088201527f6164647265737320737761704f7574707574546f6b656e2c0000000000000000601e820152751d5a5b9d0c8d4d881b5a5b94ddd85c13dd5d1c1d5d0b60521b603682015270189e5d195ccccc881b595d1859185d184b607a1b604c82015273627974657320616666696c69617465466565732960601b605d82015260710190565b60008351614eac818460208801613d4a565b835190830190614ec0818360208801613d4a565b01949350505050565b6f52657175657374207769746e6573732960801b815260008351614ef4816010850160208801613d4a565b835190830190614f0b816010840160208801613d4a565b01601001949350505050565b6000610140614f3a838a5180516001600160a01b03168252602090810151910152565b6020890151604084015260408901516060840152614f6e608084018980516001600160a01b03168252602090810151910152565b6001600160a01b03871660c084015260e083018690526101008301819052614f9881840186613d6e565b9050828103610120840152614fad8185613d6e565b9998505050505050505050565b6001600160a01b0385811682526020820185905283166040820152608060608201819052600090614b4390830184613d6e565b60006101208251818552615003828601826146ea565b915050602083015161502060208601826001600160a01b03169052565b5060408301516040850152606083015160608501526080830151848203608086015261504c8282613d6e565b91505060a083015184820360a08601526150668282613d6e565b91505060c083015161508360c08601826001600160a01b03169052565b5060e083015184820360e086015261509b8282613d6e565b915050610100808401516150b9828701826001600160a01b03169052565b5090949350505050565b8781526001600160a01b03878116602083015260408201879052606082018690528481166080830152831660a082015260e060c08201819052600090614fad90830184614fed565b601f821115610def57600081815260208120601f850160051c810160208610156151325750805b601f850160051c820191505b8181101561184b5782815560010161513e565b81516001600160401b0381111561516a5761516a6140c6565b61517e816151788454614040565b8461510b565b602080601f8311600181146151b3576000841561519b5750858301515b600019600386901b1c1916600185901b17855561184b565b600085815260208120601f198616915b828110156151e2578886015182559484019460019091019084016151c3565b50858210156152005787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000613bce6020830184614fed565b6001600160e01b0319813581811691600485101561524b5780818660040360031b1b83161692505b505092915050565b6000808585111561526357600080fd5b8386111561527057600080fd5b5050820193919092039150565b600082601f83011261528e57600080fd5b8135602061529e614bb783614b86565b82815260059290921b840181019181810190868411156152bd57600080fd5b8286015b848110156152d857803583529183019183016152c1565b509695505050505050565b6000806000606084860312156152f857600080fd5b83356001600160401b038082111561530f57600080fd5b818601915086601f83011261532357600080fd5b81356020615333614bb783614b86565b82815260059290921b8401810191818101908a84111561535257600080fd5b948201945b8386101561537057853582529482019490820190615357565b9750508701359250508082111561538657600080fd5b6153928783880161527d565b935060408601359150808211156153a857600080fd5b506153b58682870161527d565b9150509250925092565b8e8152602081018e9052604081018d9052606081018c90526001600160a01b038b811660808301528a811660a083015289811660c0830152881660e08201526101c0810163ffffffff88166101008301526001600160a01b0387166101208301528561014083015261543d6101608301866001600160a01b03169052565b6101808201939093526101a001529c9b505050505050505050505050565b82815260008251615473816020850160208701613d4a565b91909101602001939250505056fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a264697066735822122054cdd9723bc8d508b017a4b2e78f41d7a759e6d74bd3b9fe19ec9c1968802c2e64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a5acba07788f16b4790fcbb09ca3b7fc8dd053a2000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
-----Decoded View---------------
Arg [0] : _owner (address): 0xa5acBA07788f16B4790FCBb09cA3b7Fc8dd053A2
Arg [1] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000a5acba07788f16b4790fcbb09ca3b7fc8dd053a2
Arg [1] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
GNO | 100.00% | $0.999954 | 14.2625 | $14.26 |
[ 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.