Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
MagpieCCTPBridge
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import {Ownable2Step} from "openzeppelin-solidity/contracts/access/Ownable2Step.sol"; import {Pausable} from "openzeppelin-solidity/contracts/security/Pausable.sol"; import {Address} from "openzeppelin-solidity/contracts/utils/Address.sol"; import {IMagpieCCTPBridge} from "./interfaces/IMagpieCCTPBridge.sol"; import {IAxelarGateway} from "./interfaces/axelar/IAxelarGateway.sol"; import {IAxelarGasService} from "./interfaces/axelar/IAxelarGasService.sol"; import {IReceiver} from "./interfaces/cctp/IReceiver.sol"; import {LibAsset} from "./libraries/LibAsset.sol"; import {LibBridge, DepositData, SwapData} from "./libraries/LibBridge.sol"; import {LibRouter, SwapData} from "./libraries/LibRouter.sol"; error InvalidCaller(); error ReentrancyError(); error DepositIsNotFound(); error InvalidAddress(); error NotApprovedByGateway(); error MintFailed(); error BurnFailed(); contract MagpieCCTPBridge is IMagpieCCTPBridge, Ownable2Step, Pausable { using LibAsset for address; mapping(address => bool) public internalCaller; address public weth; bytes32 public networkIdAndRouterAddress; uint64 public swapSequence; mapping(bytes32 => mapping(address => uint256)) public deposit; address public swapFeeAddress; address public tokenMessengerAddress; address public messageTransmitterAddress; address public gatewayAddress; address public gasReceiverAddress; /// @dev Restricts swap functions with signatures to only be called by whitelisted internal caller. modifier onlyInternalCaller() { if (!internalCaller[msg.sender]) { revert InvalidCaller(); } _; } /// @dev See {IMagpieCCTPBridge-updateInternalCaller} function updateInternalCaller(address caller, bool value) external onlyOwner { internalCaller[caller] = value; emit UpdateInternalCaller(msg.sender, caller, value); } /// @dev See {IMagpieCCTPBridge-updateWeth} function updateWeth(address value) external onlyOwner { weth = value; } /// @dev See {IMagpieCCTPBridge-updateNetworkIdAndRouterAddress} function updateNetworkIdAndRouterAddress(bytes32 value) external onlyOwner { networkIdAndRouterAddress = value; } /// @dev See {IMagpieCCTPBridge-updateSwapFeeAddress} function updateSwapFeeAddress(address value) external onlyOwner { swapFeeAddress = value; } /// @dev See {IMagpieCCTPBridge-updateTokenMessengerAddress} function updateTokenMessengerAddress(address value) external onlyOwner { tokenMessengerAddress = value; } /// @dev See {IMagpieCCTPBridge-updateMessageTransmitterAddress} function updateMessageTransmitterAddress(address value) external onlyOwner { messageTransmitterAddress = value; } /// @dev See {IMagpieCCTPBridge-updateGatewayAddress} function updateGatewayAddress(address value) external onlyOwner { gatewayAddress = value; } /// @dev See {IMagpieCCTPBridge-gasReceiverAddress} function updateGasReceiverAddress(address value) external onlyOwner { gasReceiverAddress = value; } /// @dev See {IMagpieCCTPBridge-pause} function pause() public onlyOwner whenNotPaused { _pause(); } /// @dev See {IMagpieCCTPBridge-unpause} function unpause() public onlyOwner whenPaused { _unpause(); } /// @dev See {IMagpieCCTPBridge-swapInWithMagpieSignature} function swapInWithMagpieSignature(bytes calldata) external payable whenNotPaused returns (uint256 amountOut) { SwapData memory swapData = LibRouter.getData(); amountOut = swapIn(swapData, true); } /// @dev See {IMagpieCCTPBridge-swapInWithUserSignature} function swapInWithUserSignature(bytes calldata) external payable onlyInternalCaller returns (uint256 amountOut) { SwapData memory swapData = LibRouter.getData(); if (swapData.fromAssetAddress.isNative()) { revert InvalidAddress(); } amountOut = swapIn(swapData, false); } /// @dev Verifies the signature for a swap operation. /// @param swapData The SwapData struct containing swap details. /// @param useCaller Flag indicating whether to use the caller's address for verification. /// @return signer The address of the signer if the signature is valid. function verifySignature(SwapData memory swapData, bool useCaller) private view returns (address) { uint256 messagePtr; bool hasAffiliate = swapData.hasAffiliate; uint256 swapMessageLength = hasAffiliate ? 384 : 320; uint256 messageLength = swapMessageLength + 320; assembly { messagePtr := mload(0x40) mstore(0x40, add(messagePtr, messageLength)) // hasAffiliate switch hasAffiliate case 1 { // keccak256("Swap(address srcBridge,address srcSender,address srcRecipient,address srcFromAsset,address srcToAsset,uint256 srcDeadline,uint256 srcAmountOutMin,uint256 srcSwapFee,uint256 srcAmountIn,address affiliate,uint256 affiliateFee,bytes32 dstRecipient,bytes32 dstFromAsset,bytes32 dstToAsset,uint256 dstAmountOutMin,uint256 dstSwapFee,uint16 dstNetworkId,bytes32 dstBridge,uint32 bridgeDomain,string bridgeAddress,string bridgeChain)") mstore(messagePtr, 0x112d7d894fe0b136fbc52b80f6940fb79db28e03d78dd281e952df731f3e5ff1) } default { // keccak256("Swap(address srcBridge,address srcSender,address srcRecipient,address srcFromAsset,address srcToAsset,uint256 srcDeadline,uint256 srcAmountOutMin,uint256 srcSwapFee,uint256 srcAmountIn,bytes32 dstRecipient,bytes32 dstFromAsset,bytes32 dstToAsset,uint256 dstAmountOutMin,uint256 dstSwapFee,uint16 dstNetworkId,bytes32 dstBridge,uint32 bridgeDomain,string bridgeAddress,string bridgeChain)") mstore(messagePtr, 0x6d270d8b96a17d623996c9fcafb1b091927d68dcaab797c0f5dd271e918c2eeb) } let bridgeDataPosition := shr(240, calldataload(add(66, calldataload(36)))) let currentMessagePtr := add(messagePtr, swapMessageLength) mstore(currentMessagePtr, calldataload(bridgeDataPosition)) // toAddress currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, calldataload(add(bridgeDataPosition, 32))) // fromAssetAddress currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, calldataload(add(bridgeDataPosition, 64))) // toAssetAddress currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, calldataload(add(bridgeDataPosition, 96))) // amountOutMin currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, calldataload(add(bridgeDataPosition, 128))) // swapFee currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, shr(240, calldataload(add(bridgeDataPosition, 160)))) // recipientNetworkId currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, calldataload(add(bridgeDataPosition, 162))) // recipientAddress currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, shr(224, calldataload(add(bridgeDataPosition, 194)))) // bridgeDomain let bridgeAddressLength := shr(240, calldataload(add(bridgeDataPosition, 198))) let bridgeAddressPtr := mload(0x40) calldatacopy(bridgeAddressPtr, add(bridgeDataPosition, 200), bridgeAddressLength) currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, keccak256(bridgeAddressPtr, bridgeAddressLength)) // bridgeAddress let bridgeChainLength := shr(240, calldataload(add(add(bridgeDataPosition, 200), bridgeAddressLength))) let bridgeChainPtr := add(bridgeAddressPtr, bridgeAddressLength) calldatacopy(bridgeChainPtr, add(add(bridgeDataPosition, 202), bridgeAddressLength), bridgeChainLength) mstore(0x40, add(bridgeChainPtr, bridgeChainLength)) currentMessagePtr := add(currentMessagePtr, 32) mstore(currentMessagePtr, keccak256(bridgeChainPtr, bridgeChainLength)) // bridgeChain } return LibRouter.verifySignature( // keccak256(bytes("Magpie CCTP Bridge")), 0x31da2c74f8c27ef76897147f0ad12d949a674ee71cd159480d92be2858340871, // keccak256(bytes("1")), 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6, swapData, messagePtr, messageLength, useCaller, 2 ); } /// @dev Executes an inbound swap operation. /// @param useCaller Flag indicating whether to use the caller's address for the swap. /// @return amountOut The amount received as output from the swap operation. function swapIn(SwapData memory swapData, bool useCaller) private returns (uint256 amountOut) { swapSequence++; uint64 currentSwapSequence = swapSequence; uint16 networkId; address routerAddress; assembly { let currentNetworkIdAndRouterAddress := sload(networkIdAndRouterAddress.slot) networkId := shr(240, currentNetworkIdAndRouterAddress) routerAddress := shr(16, shl(16, currentNetworkIdAndRouterAddress)) } address fromAddress = verifySignature(swapData, useCaller); if (swapData.hasPermit) { LibRouter.permit(swapData, fromAddress); } LibRouter.transferFees(swapData, fromAddress, swapData.swapFee == 0 ? address(0) : swapFeeAddress); bytes memory encodedDepositData = new bytes(236); // 194 + 42 LibBridge.fillEncodedDepositData(encodedDepositData, networkId, currentSwapSequence); bytes32 depositDataHash = keccak256(encodedDepositData); amountOut = LibBridge.swapIn(swapData, encodedDepositData, fromAddress, routerAddress, weth); bridgeIn(LibBridge.getFee(swapData), fromAddress, swapData.toAssetAddress, amountOut, depositDataHash); if (currentSwapSequence != swapSequence) { revert ReentrancyError(); } } /// @dev Bridges an inbound asset transfer into the contract. /// @param transferFee Data transfer fee that has to be payed in native token. /// @param refundAddress If the operation fails, tokens will be transferred to this address. /// @param toAssetAddress The address of the asset being bridged into the contract. /// @param amount The amount of the asset being transferred into the contract. /// @param depositDataHash Encoded hash related to the crosschain transaction. function bridgeIn( uint256 transferFee, address refundAddress, address toAssetAddress, uint256 amount, bytes32 depositDataHash ) private { toAssetAddress.approve(tokenMessengerAddress, amount); uint256 ptr; assembly { let bridgeDataPosition := shr(240, calldataload(add(66, calldataload(36)))) ptr := mload(0x40) mstore(0x40, add(ptr, 196)) mstore(ptr, 0xf856ddb600000000000000000000000000000000000000000000000000000000) // depositForBurnWithCaller mstore(add(ptr, 4), amount) mstore(add(ptr, 36), shr(224, calldataload(add(bridgeDataPosition, 194)))) // bridgeDomain mstore(add(ptr, 68), calldataload(add(bridgeDataPosition, 162))) // receiver mstore(add(ptr, 100), toAssetAddress) mstore(add(ptr, 132), calldataload(add(bridgeDataPosition, 162))) // receiver } if (!tokenMessengerAddress.execute(0, ptr, 164, ptr + 164, 32)) { revert BurnFailed(); } dataIn(transferFee, depositDataHash, amount, refundAddress); } /// @dev Executes an inbound data transfer. /// @param transferFee Data transfer fee that has to be payed in native token. /// @param depositDataHash Encoded hash related to the crosschain transaction. /// @param amount The amount of the asset being transferred into the contract. /// @param refundAddress If the operation fails, tokens will be transferred to this address. function dataIn(uint256 transferFee, bytes32 depositDataHash, uint256 amount, address refundAddress) private { bytes memory payload = new bytes(96); string memory bridgeAddress; string memory bridgeChain; assembly { let bridgeDataPosition := shr(240, calldataload(add(66, calldataload(36)))) let bridgeAddressLength := shr(240, calldataload(add(bridgeDataPosition, 198))) bridgeAddress := mload(0x40) mstore(bridgeAddress, bridgeAddressLength) calldatacopy(add(bridgeAddress, 32), add(bridgeDataPosition, 200), bridgeAddressLength) let bridgeChainLength := shr(240, calldataload(add(add(bridgeDataPosition, 200), bridgeAddressLength))) bridgeChain := add(add(bridgeAddress, 32), bridgeAddressLength) mstore(bridgeChain, bridgeChainLength) calldatacopy( add(bridgeChain, 32), add(add(bridgeDataPosition, 202), bridgeAddressLength), bridgeChainLength ) mstore(0x40, add(add(bridgeChain, 32), bridgeChainLength)) mstore(add(payload, 32), depositDataHash) mstore(add(payload, 64), amount) mstore(add(payload, 96), calldataload(add(bridgeDataPosition, 32))) // destination chain fromAssetAddress } IAxelarGasService(gasReceiverAddress).payNativeGasForContractCall{value: transferFee}( address(this), bridgeChain, bridgeAddress, payload, refundAddress ); IAxelarGateway(gatewayAddress).callContract(bridgeChain, bridgeAddress, payload); } event Deposit(bytes32 depositDataHash, uint256 amount); /// @dev See {IMagpieCCTPBridge-execute} function execute( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload ) external { if ( !IAxelarGateway(gatewayAddress).validateContractCall( commandId, sourceChain, sourceAddress, keccak256(payload) ) ) { revert NotApprovedByGateway(); } addDeposit(payload); } /// @dev Add validated deposit. /// @param payload Data transfer payload. function addDeposit(bytes memory payload) private { bytes32 depositDataHash; uint256 amount; address assetAddress; assembly { depositDataHash := mload(add(payload, 32)) amount := mload(add(payload, 64)) assetAddress := mload(add(payload, 96)) } deposit[depositDataHash][assetAddress] += amount; emit Deposit(depositDataHash, amount); } /// @dev See {IMagpieCCTPBridge-swapOut} function swapOut(bytes calldata) external onlyInternalCaller returns (uint256 amountOut) { address routerAddress; uint16 networkId; assembly { let currentNetworkIdAndRouterAddress := sload(networkIdAndRouterAddress.slot) networkId := shr(240, currentNetworkIdAndRouterAddress) routerAddress := shr(16, shl(16, currentNetworkIdAndRouterAddress)) } SwapData memory swapData = LibRouter.getData(); bytes memory message; bytes memory attestation; uint256 messageAmount; assembly { let cctpBridgeDataPosition := add(shr(240, calldataload(add(66, calldataload(36)))), 42) // bridgeDataPosition + (networkId, senderAddress, swapSequence) let messageLength := shr(240, calldataload(cctpBridgeDataPosition)) message := mload(0x40) mstore(message, messageLength) calldatacopy(add(message, 32), add(cctpBridgeDataPosition, 2), messageLength) let attestationLength := shr(240, calldataload(add(add(cctpBridgeDataPosition, 2), messageLength))) attestation := add(add(message, 32), messageLength) mstore(attestation, attestationLength) calldatacopy(add(attestation, 32), add(add(cctpBridgeDataPosition, 4), messageLength), attestationLength) mstore(0x40, add(add(attestation, 32), attestationLength)) messageAmount := mload(add(message, 216)) } if (!IReceiver(messageTransmitterAddress).receiveMessage(message, attestation)) { revert MintFailed(); } bytes32 depositDataHash = LibBridge.getDepositDataHash(swapData, networkId, address(this)); uint256 depositAmount = deposit[depositDataHash][swapData.fromAssetAddress]; if (depositAmount == 0 || messageAmount != depositAmount) { revert DepositIsNotFound(); } deposit[depositDataHash][swapData.fromAssetAddress] = 0; amountOut = LibBridge.swapOut(swapData, depositAmount, depositDataHash, routerAddress, weth, swapFeeAddress); } /// @dev See {IMagpieCCTPBridge-multicall} function multicall(bytes[] calldata data) external onlyOwner returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } /// @dev Used to receive ethers receive() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IBridge { event SwapIn( address indexed fromAddress, address indexed toAddress, address fromAssetAddress, address toAssetAddress, uint256 amountIn, uint256 amountOut, bytes encodedDepositData ); event SwapOut( address indexed fromAddress, address indexed toAddress, address fromAssetAddress, address toAssetAddress, uint256 amountIn, uint256 amountOut, bytes32 depositDataHash ); event UpdateInternalCaller(address indexed sender, address caller, bool value); /// @dev Allows the owner to update the whitelisted internal callers. /// @param caller Caller address. /// @param value Disable or enable the related caller. function updateInternalCaller(address caller, bool value) external; /// @dev Allows the owner to update weth. /// @param value New weth address. function updateWeth(address value) external; /// @dev Allows the owner to update Magpie networkId and routerAddress. /// @param value Compressed networkId and routerAddress. function updateNetworkIdAndRouterAddress(bytes32 value) external; /// @dev Makes it possible to execute multiple functions in the same transaction. function multicall(bytes[] calldata data) external returns (bytes[] memory results); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import {IBridge} from "./IBridge.sol"; interface IMagpieCCTPBridge is IBridge { /// @dev Allows the owner to update the swap fee receiver. /// @param value Swap fee receiver address. function updateSwapFeeAddress(address value) external; /// @dev Allows the owner to update CCTP token messenger address. /// @param value New tokenMessengerAddress. function updateTokenMessengerAddress(address value) external; /// @param value New messageTransmitterAddress. function updateMessageTransmitterAddress(address value) external; /// @dev Allows the owner to update Axelar gateway address. /// @param value New gatewayAddress. function updateGatewayAddress(address value) external; /// @dev Allows the owner to update Axelar gas receiver address. /// @param value New gasReceiverAddress. function updateGasReceiverAddress(address value) external; /// @dev Called by the owner to pause, triggers stopped state. function pause() external; /// @dev Called by the owner to unpause, returns to normal state. function unpause() external; /// @dev Executes an axelar command from a source chain. /// @param commandId The unique identifier for the command to be executed. /// @param sourceChain The name of the chain from which the command originated. /// @param sourceAddress The address on the source chain that initiated the command. /// @param payload The actual data or instructions to be executed, encoded as bytes. function execute( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes calldata payload ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IMagpieRouterV3 { event UpdateInternalCaller(address indexed sender, address caller, bool value); /// @dev Allows the owner to update the whitelisted internal callers. /// @param caller Caller address. /// @param value Disable or enable the related caller. function updateInternalCaller(address caller, bool value) external; event UpdateBridge(address indexed sender, address caller, bool value); /// @dev Allows the owner to update the whitelisted bridges. /// @param caller Caller address. /// @param value Disable or enable the related caller. function updateBridge(address caller, bool value) external; /// @dev Allows the owner to update the swap fee receiver. /// @param value Swap fee receiver address. function updateSwapFeeAddress(address value) external; /// @dev Called by the owner to pause, triggers stopped state. function pause() external; /// @dev Called by the owner to unpause, returns to normal state. function unpause() external; event Swap( address indexed fromAddress, address indexed toAddress, address fromAssetAddress, address toAssetAddress, uint256 amountIn, uint256 amountOut ); /// @dev Makes it possible to execute multiple functions in the same transaction. function multicall(bytes[] calldata data) external returns (bytes[] memory results); /// @dev Provides an external interface to estimate the gas cost of the last hop in a route. /// @return amountOut The amount received after swapping. /// @return gasUsed The cost of gas while performing the swap. function estimateSwapGas(bytes calldata swapArgs) external payable returns (uint256 amountOut, uint256 gasUsed); /// @dev Performs token swap with magpie signature. /// @return amountOut The amount received after swapping. function swapWithMagpieSignature(bytes calldata swapArgs) external payable returns (uint256 amountOut); /// @dev Performs token swap with a user signature. /// @return amountOut The amount received after swapping. function swapWithUserSignature(bytes calldata swapArgs) external payable returns (uint256 amountOut); /// @dev Performs token swap without a signature (data will be validated in the bridge) without triggering event. /// @return amountOut The amount received after swapping. function swapWithoutSignature(bytes calldata swapArgs) external payable returns (uint256 amountOut); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; /** * @title IAxelarGasService Interface * @notice This is an interface for the AxelarGasService contract which manages gas payments * and refunds for cross-chain communication on the Axelar network. * @dev This interface inherits IUpgradable */ interface IAxelarGasService { /** * @notice Pay for gas using native currency for a contract call on a destination chain. * @dev This function is called on the source chain before calling the gateway to execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call * @param refundAddress The address where refunds, if any, should be sent */ function payNativeGasForContractCall( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address refundAddress ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IAxelarGateway { function callContract( string calldata destinationChain, string calldata contractAddress, bytes calldata payload ) external; function validateContractCall( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; /** * @title IReceiver * @notice Receives messages on destination chain and forwards them to IMessageDestinationHandler */ interface IReceiver { /** * @notice Receives an incoming message, validating the header and passing * the body to application-specific handler. * @param message The message raw bytes * @param signature The message signature * @return success bool, true if successful */ function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "../interfaces/IWETH.sol"; error AssetNotReceived(); error ApprovalFailed(); error TransferFromFailed(); error TransferFailed(); error FailedWrap(); error FailedUnwrap(); library LibAsset { using LibAsset for address; address constant NATIVE_ASSETID = address(0); /// @dev Checks if the given address (self) represents a native asset (Ether). /// @param self The asset that will be checked for a native token. /// @return Flag to identify if the asset is native or not. function isNative(address self) internal pure returns (bool) { return self == NATIVE_ASSETID; } /// @dev Wraps the specified asset. /// @param self The asset that will be wrapped. function wrap(address self, uint256 amount) internal { uint256 ptr; assembly { ptr := mload(0x40) mstore(0x40, add(ptr, 4)) mstore(ptr, 0xd0e30db000000000000000000000000000000000000000000000000000000000) } if (!execute(self, amount, ptr, 4, 0, 0)) { revert FailedWrap(); } } /// @dev Unwraps the specified asset. /// @param self The asset that will be unwrapped. function unwrap(address self, uint256 amount) internal { uint256 ptr; assembly { ptr := mload(0x40) mstore(0x40, add(ptr, 36)) mstore(ptr, 0x2e1a7d4d00000000000000000000000000000000000000000000000000000000) mstore(add(ptr, 4), amount) } if (!execute(self, 0, ptr, 36, 0, 0)) { revert FailedUnwrap(); } } /// @dev Retrieves the balance of the current contract for a given asset (self). /// @param self Asset whose balance needs to be found. /// @return Balance of the specific asset. function getBalance(address self) internal view returns (uint256) { return getBalanceOf(self, address(this)); } /// @dev Retrieves the balance of the target address for a given asset (self). /// @param self Asset whose balance needs to be found. /// @param targetAddress The address where the balance is checked from. /// @return amount Balance of the specific asset. function getBalanceOf(address self, address targetAddress) internal view returns (uint256 amount) { assembly { switch self case 0 { amount := balance(targetAddress) } default { let currentInputPtr := mload(0x40) mstore(0x40, add(currentInputPtr, 68)) mstore(currentInputPtr, 0x70a0823100000000000000000000000000000000000000000000000000000000) mstore(add(currentInputPtr, 4), targetAddress) let currentOutputPtr := add(currentInputPtr, 36) if iszero(staticcall(gas(), self, currentInputPtr, 36, currentOutputPtr, 32)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } amount := mload(currentOutputPtr) } } } /// @dev Performs a safe transferFrom operation for a given asset (self) from one address (from) to another address (to). /// @param self Asset that will be transferred. /// @param from Address that will send the asset. /// @param to Address that will receive the asset. /// @param amount Transferred amount. function transferFrom(address self, address from, address to, uint256 amount) internal { uint256 ptr; assembly { ptr := mload(0x40) mstore(0x40, add(ptr, 100)) mstore(ptr, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(ptr, 4), from) mstore(add(ptr, 36), to) mstore(add(ptr, 68), amount) } if (!execute(self, 0, ptr, 100, 0, 0)) { revert TransferFromFailed(); } } /// @dev Transfers a given amount of an asset (self) to a recipient address (recipient). /// @param self Asset that will be transferred. /// @param recipient Address that will receive the transferred asset. /// @param amount Transferred amount. function transfer(address self, address recipient, uint256 amount) internal { if (self.isNative()) { (bool success, ) = payable(recipient).call{value: amount}(""); if (!success) { revert TransferFailed(); } } else { uint256 ptr; assembly { ptr := mload(0x40) mstore(0x40, add(ptr, 68)) mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(ptr, 4), recipient) mstore(add(ptr, 36), amount) } if (!execute(self, 0, ptr, 68, 0, 0)) { revert TransferFailed(); } } } /// @dev Approves a spender address (spender) to spend a specified amount of an asset (self). /// @param self The asset that will be approved. /// @param spender Address of a contract that will spend the owners asset. /// @param amount Asset amount that can be spent. function approve(address self, address spender, uint256 amount) internal { uint256 ptr; assembly { ptr := mload(0x40) mstore(0x40, add(ptr, 68)) mstore(ptr, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(ptr, 4), spender) mstore(add(ptr, 36), amount) } if (!execute(self, 0, ptr, 68, 0, 0)) { assembly { mstore(add(ptr, 36), 0) } if (!execute(self, 0, ptr, 68, 0, 0)) { revert ApprovalFailed(); } assembly { mstore(add(ptr, 36), amount) } if (!execute(self, 0, ptr, 68, 0, 0)) { revert ApprovalFailed(); } } } function permit( address self, address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { assembly { let ptr := mload(0x40) mstore(0x40, add(ptr, 228)) mstore(ptr, 0xd505accf00000000000000000000000000000000000000000000000000000000) mstore(add(ptr, 4), owner) mstore(add(ptr, 36), spender) mstore(add(ptr, 68), amount) mstore(add(ptr, 100), deadline) mstore(add(ptr, 132), v) mstore(add(ptr, 164), r) mstore(add(ptr, 196), s) let success := call(gas(), self, 0, ptr, 228, 0, 0) } } /// @dev Determines if a call was successful. /// @param target Address of the target contract. /// @param success To check if the call to the contract was successful or not. /// @param data The data was sent while calling the target contract. /// @return result The success of the call. function isSuccessful(address target, bool success, bytes memory data) private view returns (bool result) { if (success) { if (data.length == 0) { // isContract if (target.code.length > 0) { result = true; } } else { assembly { result := mload(add(data, 32)) } } } } /// @dev Executes a low level call. function execute( address self, uint256 currentNativeAmount, uint256 currentInputPtr, uint256 currentInputLength, uint256 currentOutputPtr, uint256 outputLength ) internal returns (bool result) { assembly { function isSuccessfulCall(targetAddress) -> isSuccessful { switch iszero(returndatasize()) case 1 { if gt(extcodesize(targetAddress), 0) { isSuccessful := 1 } } case 0 { returndatacopy(0, 0, 32) isSuccessful := gt(mload(0), 0) } } if iszero( call( gas(), self, currentNativeAmount, currentInputPtr, currentInputLength, currentOutputPtr, outputLength ) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } result := isSuccessfulCall(self) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import {IMagpieRouterV3} from "../interfaces/IMagpieRouterV3.sol"; import {IBridge} from "../interfaces/IBridge.sol"; import {LibAsset} from "./LibAsset.sol"; import {LibRouter, SwapData} from "./LibRouter.sol"; struct DepositData { address toAddress; address fromAssetAddress; address toAssetAddress; uint256 amountOutMin; uint256 swapFee; uint256 amountIn; uint16 networkId; // Source network id that is defined by Magpie protocol for each chain bytes32 senderAddress; // The sender address in bytes32 uint64 swapSequence; // Swap sequence (unique identifier) of the crosschain swap } error InvalidSwapData(); error InvalidSignature(); error InvalidToAddress(); error InvalidAmountIn(); error InvalidSwapFee(); error InvalidDepositAmount(); library LibBridge { using LibAsset for address; function getFee(SwapData memory swapData) internal view returns (uint256 bridgeFee) { bridgeFee = swapData.fromAssetAddress.isNative() ? msg.value - (swapData.amountIn + swapData.swapFee + swapData.affiliateFee) : msg.value; } function decodeDepositDataHash(bytes memory payload) internal pure returns (bytes32 depositDataHash) { assembly { depositDataHash := mload(add(payload, 32)) } } function encodeDepositDataHash(bytes32 depositDataHash) internal pure returns (bytes memory payload) { payload = new bytes(32); assembly { mstore(add(payload, 32), depositDataHash) } } function getDepositDataHash( SwapData memory swapData, uint16 recipientNetworkId, address recipientAddress ) internal pure returns (bytes32 depositDataHash) { assembly { let depositDataPtr := mload(0x40) mstore(0x40, add(depositDataPtr, 236)) mstore(depositDataPtr, mload(swapData)) // toAddress mstore(add(depositDataPtr, 32), mload(add(swapData, 32))) // fromAssetAddress mstore(add(depositDataPtr, 64), mload(add(swapData, 64))) // toAssetAddress mstore(add(depositDataPtr, 96), mload(add(swapData, 128))) // amountOutMin mstore(add(depositDataPtr, 128), mload(add(swapData, 160))) // swapFee mstore(add(depositDataPtr, 160), shl(240, recipientNetworkId)) // recipientNetworkId mstore(add(depositDataPtr, 162), recipientAddress) // recipientAddress calldatacopy(add(depositDataPtr, 194), shr(240, calldataload(add(66, calldataload(36)))), 42) // networkId, senderAddress, swapSequence depositDataHash := keccak256(depositDataPtr, 236) } } /// @dev Fills the specified variable with encoded deposit data. /// @param encodedDepositData Variable / Placeholder that will be filled with the deposit data. /// @param networkId The identifier of the sender network. /// @param swapSequence The current swap sequence number. function fillEncodedDepositData( bytes memory encodedDepositData, uint16 networkId, uint64 swapSequence ) internal view { assembly { // DepositData calldatacopy(add(encodedDepositData, 32), shr(240, calldataload(add(66, calldataload(36)))), 194) // TransferKey mstore(add(encodedDepositData, 226), shl(240, networkId)) // 194 + 32 mstore(add(encodedDepositData, 228), address()) // 194 + 32 + 2 mstore(add(encodedDepositData, 260), shl(192, swapSequence)) // 194 + 32 + 34 } } /// @dev Executes a swap operation using a specified router and native amount. /// @param routerAddress The address of the router contract for the swap. /// @param nativeAmount The amount of native currency to be swapped. /// @return amountOut The amount received as output from the swap operation. function swap(address routerAddress, uint256 nativeAmount) private returns (uint256 amountOut, bool success) { assembly { let inputPtr := mload(0x40) let inputLength := shr(240, calldataload(add(66, calldataload(36)))) // bridgeDataPosition let payloadLength := sub(inputLength, 68) mstore(0x40, add(inputPtr, inputLength)) mstore(inputPtr, 0x158f689400000000000000000000000000000000000000000000000000000000) // swapWithoutSignature mstore(add(inputPtr, 4), 32) mstore(add(inputPtr, 36), payloadLength) let outputPtr := mload(0x40) mstore(0x40, add(outputPtr, 32)) calldatacopy(add(inputPtr, 68), 68, payloadLength) success := call(gas(), routerAddress, nativeAmount, inputPtr, inputLength, outputPtr, 32) if eq(success, 1) { amountOut := mload(outputPtr) } } } /// @dev Executes an inbound swap operation using provided data and addresses. /// @param swapData The SwapData struct containing swap details. /// @param encodedDepositData Encoded data related to the deposit. /// @param fromAddress The address from which the swap originates. /// @param routerAddress The address of the router contract for the swap. /// @param weth The address of the Wrapped Ether contract. /// @return amountOut The amount received as output from the swap operation. function swapIn( SwapData memory swapData, bytes memory encodedDepositData, address fromAddress, address routerAddress, address weth ) internal returns (uint256 amountOut) { if (swapData.toAddress != address(this)) { revert InvalidToAddress(); } if (swapData.fromAssetAddress.isNative()) { if (msg.value < (swapData.amountIn + swapData.swapFee + swapData.affiliateFee)) { revert InvalidAmountIn(); } } if (swapData.fromAssetAddress.isNative() && swapData.toAssetAddress == weth) { weth.wrap(swapData.amountIn); amountOut = swapData.amountIn; } else if (swapData.fromAssetAddress == weth && swapData.toAssetAddress.isNative()) { swapData.fromAssetAddress.transferFrom(fromAddress, address(this), swapData.amountIn); weth.unwrap(swapData.amountIn); amountOut = swapData.amountIn; } else if (swapData.fromAssetAddress == swapData.toAssetAddress) { swapData.fromAssetAddress.transferFrom(fromAddress, address(this), swapData.amountIn); amountOut = swapData.amountIn; } else { uint256 nativeAmount = 0; if (swapData.fromAssetAddress.isNative()) { nativeAmount = swapData.amountIn; } else { swapData.fromAssetAddress.transferFrom(fromAddress, address(this), swapData.amountIn); swapData.fromAssetAddress.approve(routerAddress, swapData.amountIn); } bool success = false; (amountOut, success) = swap(routerAddress, nativeAmount); if (!success) { assembly { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } emit IBridge.SwapIn( fromAddress, swapData.toAddress, swapData.fromAssetAddress, swapData.toAssetAddress, swapData.amountIn + swapData.swapFee + swapData.affiliateFee, amountOut, encodedDepositData ); } /// @dev Executes an outbound swap operation using provided swap and deposit data. /// @param swapData The SwapData struct containing swap details. /// @param depositAmount The bridged amount that will be swapped. /// @param routerAddress The address of the router contract for the swap. /// @param weth The address of the Wrapped Ether contract. /// @return amountOut The amount received as output from the swap operation. function swapOut( SwapData memory swapData, uint256 depositAmount, bytes32 depositDataHash, address routerAddress, address weth, address swapFeeAddress ) internal returns (uint256 amountOut) { if (depositAmount != swapData.amountIn + swapData.swapFee) { revert InvalidDepositAmount(); } if (swapData.swapFee > 0) { swapData.fromAssetAddress.transfer(swapFeeAddress, swapData.swapFee); } if (swapData.amountIn > 0) { if (swapData.fromAssetAddress == weth && swapData.toAssetAddress.isNative()) { weth.unwrap(swapData.amountIn); swapData.fromAssetAddress.transfer(swapData.toAddress, swapData.amountIn); } else if (swapData.fromAssetAddress.isNative() && swapData.toAssetAddress == weth) { weth.wrap(swapData.amountIn); swapData.fromAssetAddress.transfer(swapData.toAddress, swapData.amountIn); amountOut = swapData.amountIn; } else if (swapData.fromAssetAddress == swapData.toAssetAddress) { swapData.fromAssetAddress.transfer(swapData.toAddress, swapData.amountIn); amountOut = swapData.amountIn; } else { // We dont need signature, we validate against crosschain message uint256 nativeAmount = 0; if (swapData.fromAssetAddress.isNative()) { nativeAmount = swapData.amountIn; } else { swapData.fromAssetAddress.approve(routerAddress, swapData.amountIn); } bool success = false; (amountOut, success) = swap(routerAddress, nativeAmount); if (!success) { if (!swapData.fromAssetAddress.isNative()) { swapData.fromAssetAddress.approve(routerAddress, 0); } swapData.fromAssetAddress.transfer(swapData.toAddress, swapData.amountIn); swapData.toAssetAddress = swapData.fromAssetAddress; amountOut = swapData.amountIn; } } } emit IBridge.SwapOut( msg.sender, swapData.toAddress, swapData.fromAssetAddress, swapData.toAssetAddress, swapData.amountIn + swapData.swapFee, amountOut, depositDataHash ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import {LibAsset} from "../libraries/LibAsset.sol"; struct SwapData { address toAddress; address fromAssetAddress; address toAssetAddress; uint256 deadline; uint256 amountOutMin; uint256 swapFee; uint256 amountIn; bool hasPermit; bool hasAffiliate; address affiliateAddress; uint256 affiliateFee; } error InvalidSignature(); error ExpiredTransaction(); library LibRouter { using LibAsset for address; /// @dev Prepares SwapData from calldata function getData() internal view returns (SwapData memory swapData) { // dataOffset: 68 + 2 assembly { let deadline := shr( shr(248, calldataload(132)), // dataOffset + 62 calldataload(shr(240, calldataload(133))) // dataOffset + 62 + 1 ) if lt(deadline, timestamp()) { // ExpiredTransaction mstore(0, 0x931997cf00000000000000000000000000000000000000000000000000000000) revert(0, 4) } mstore(swapData, shr(96, calldataload(72))) // toAddress / dataOffset + 2 mstore(add(swapData, 32), shr(96, calldataload(92))) // fromAssetAddress / dataOffset + 22 mstore(add(swapData, 64), shr(96, calldataload(112))) // toAssetAddress / dataOffset + 42 mstore(add(swapData, 96), deadline) mstore( add(swapData, 128), shr( shr(248, calldataload(135)), // dataOffset + 62 + 3 calldataload(shr(240, calldataload(136))) // dataOffset + 62 + 4 ) ) // amountOutMin mstore( add(swapData, 160), shr( shr(248, calldataload(138)), // dataOffset + 62 + 6 calldataload(shr(240, calldataload(139))) // dataOffset + 62 + 7 ) ) // swapFee mstore( add(swapData, 192), shr( shr(248, calldataload(141)), // dataOffset + 62 + 9 calldataload(shr(240, calldataload(142))) // dataOffset + 62 + 10 ) ) // amountIn // calldataload(144) // r // calldataload(176) // s // shr(248, calldataload(208)) // v let hasPermit := gt(shr(248, calldataload(209)), 0) // permit v mstore(add(swapData, 224), hasPermit) // hasPermit // calldataload(210) // permit r // calldataload(242) // permit s // calldataload(274) // permit deadline switch hasPermit case 1 { let hasAffiliate := shr(248, calldataload(277)) mstore(add(swapData, 256), hasAffiliate) // hasAffiliate if eq(hasAffiliate, 1) { mstore(add(swapData, 288), shr(96, calldataload(278))) // affiliateAddress mstore( add(swapData, 320), shr(shr(248, calldataload(298)), calldataload(shr(240, calldataload(299)))) ) // affiliateFee } } default { let hasAffiliate := shr(248, calldataload(210)) mstore(add(swapData, 256), hasAffiliate) // hasAffiliate if eq(hasAffiliate, 1) { mstore(add(swapData, 288), shr(96, calldataload(211))) // affiliateAddress mstore( add(swapData, 320), shr(shr(248, calldataload(231)), calldataload(shr(240, calldataload(232)))) ) // affiliateFee } } } } /// @dev Transfers the required fees for the swap operation from the user's account. /// @param swapData The data structure containing the details of the swap operation, including fee information. /// @param fromAddress The address of the user from whom the fees will be deducted. /// @param swapFeeAddress The address of the swap fee receiver. function transferFees(SwapData memory swapData, address fromAddress, address swapFeeAddress) internal { if (swapData.swapFee > 0) { if (swapData.fromAssetAddress.isNative()) { swapData.fromAssetAddress.transfer(swapFeeAddress, swapData.swapFee); } else { swapData.fromAssetAddress.transferFrom(fromAddress, swapFeeAddress, swapData.swapFee); } } if (swapData.affiliateFee > 0) { if (swapData.fromAssetAddress.isNative()) { swapData.fromAssetAddress.transfer(swapData.affiliateAddress, swapData.affiliateFee); } else { swapData.fromAssetAddress.transferFrom(fromAddress, swapData.affiliateAddress, swapData.affiliateFee); } } } /// @dev Grants permission for the user's asset to be used in a swap operation. /// @param swapData The data structure containing the details of the swap operation. /// @param fromAddress The address of the user who is granting permission for their asset to be used. function permit(SwapData memory swapData, address fromAddress) internal { uint8 v; bytes32 r; bytes32 s; uint256 deadline; assembly { v := shr(248, calldataload(209)) r := calldataload(210) s := calldataload(242) deadline := shr(shr(248, calldataload(274)), calldataload(shr(240, calldataload(275)))) } swapData.fromAssetAddress.permit( fromAddress, address(this), swapData.amountIn + swapData.swapFee + swapData.affiliateFee, deadline, v, r, s ); } /// @dev Recovers the signer's address from a hashed message and signature components. /// @param hash The hash of the message that was signed. /// @param r The `r` component of the signature. /// @param s The `s` component of the signature. /// @param v The `v` component of the signature. /// @return signer The address of the signer recovered from the signature. function recoverSigner(bytes32 hash, bytes32 r, bytes32 s, uint8 v) private pure returns (address signer) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert InvalidSignature(); } if (v != 27 && v != 28) { revert InvalidSignature(); } signer = ecrecover(hash, v, r, s); if (signer == address(0)) { revert InvalidSignature(); } } function getDomainSeparator(bytes32 name, bytes32 version) private view returns (bytes32) { uint256 chainId; assembly { chainId := chainid() } return keccak256( abi.encode( // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f, name, version, chainId, address(this) ) ); } /// @dev Verifies the signature for a swap operation. /// @param swapData The SwapData struct containing swap details. /// @param messagePtr Pointer to the message data in memory. /// @param messageLength Length of the message data. /// @param useCaller Flag indicating whether to use the caller's address for verification. /// @param internalCallersSlot Slot in the internal callers storage for verification. /// @return fromAddress The address of the signer / or caller if the signature is valid. function verifySignature( bytes32 name, bytes32 version, SwapData memory swapData, uint256 messagePtr, uint256 messageLength, bool useCaller, uint8 internalCallersSlot ) internal view returns (address fromAddress) { bytes32 domainSeparator = getDomainSeparator(name, version); bytes32 digest; bytes32 r; bytes32 s; uint8 v; assembly { mstore(add(messagePtr, 32), address()) mstore(add(messagePtr, 64), caller()) mstore(add(messagePtr, 96), mload(swapData)) mstore(add(messagePtr, 128), mload(add(swapData, 32))) mstore(add(messagePtr, 160), mload(add(swapData, 64))) mstore(add(messagePtr, 192), mload(add(swapData, 96))) mstore(add(messagePtr, 224), mload(add(swapData, 128))) mstore(add(messagePtr, 256), mload(add(swapData, 160))) mstore(add(messagePtr, 288), mload(add(swapData, 192))) // hasAffiliate if eq(mload(add(swapData, 256)), 1) { mstore(add(messagePtr, 320), mload(add(swapData, 288))) mstore(add(messagePtr, 352), mload(add(swapData, 320))) } let hash := keccak256(messagePtr, messageLength) messagePtr := mload(0x40) mstore(0x40, add(messagePtr, 66)) mstore(messagePtr, "\x19\x01") mstore(add(messagePtr, 2), domainSeparator) mstore(add(messagePtr, 34), hash) digest := keccak256(messagePtr, 66) r := calldataload(144) s := calldataload(176) v := shr(248, calldataload(208)) } if (useCaller) { address internalCaller = recoverSigner(digest, r, s, v); assembly { fromAddress := caller() mstore(0, internalCaller) mstore(0x20, internalCallersSlot) if iszero(eq(sload(keccak256(0, 0x40)), 1)) { // InvalidSignature mstore(0, 0x8baa579f00000000000000000000000000000000000000000000000000000000) revert(0, 4) } } } else { fromAddress = recoverSigner(digest, r, s, v); if (fromAddress == address(this)) { revert InvalidSignature(); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol) pragma solidity ^0.8.0; import "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "evmVersion": "paris", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"ApprovalFailed","type":"error"},{"inputs":[],"name":"BurnFailed","type":"error"},{"inputs":[],"name":"DepositIsNotFound","type":"error"},{"inputs":[],"name":"FailedUnwrap","type":"error"},{"inputs":[],"name":"FailedWrap","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidAmountIn","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidDepositAmount","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidToAddress","type":"error"},{"inputs":[],"name":"MintFailed","type":"error"},{"inputs":[],"name":"NotApprovedByGateway","type":"error"},{"inputs":[],"name":"ReentrancyError","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferFromFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"depositDataHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"address","name":"fromAssetAddress","type":"address"},{"indexed":false,"internalType":"address","name":"toAssetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"encodedDepositData","type":"bytes"}],"name":"SwapIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"address","name":"fromAssetAddress","type":"address"},{"indexed":false,"internalType":"address","name":"toAssetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"depositDataHash","type":"bytes32"}],"name":"SwapOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"UpdateInternalCaller","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gasReceiverAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gatewayAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"internalCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageTransmitterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"networkIdAndRouterAddress","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapFeeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"swapInWithMagpieSignature","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"swapInWithUserSignature","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"swapOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapSequence","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenMessengerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"updateGasReceiverAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"updateGatewayAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"updateInternalCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"updateMessageTransmitterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"value","type":"bytes32"}],"name":"updateNetworkIdAndRouterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"updateSwapFeeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"updateTokenMessengerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"updateWeth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001d3362000030565b6001805460ff60a01b191690556200009e565b600180546001600160a01b03191690556200004b816200004e565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612ba780620000ae6000396000f3fe6080604052600436106101dc5760003560e01c806379ba509711610102578063b8f38c7411610095578063dc0b3d2111610064578063dc0b3d211461058e578063e30c3978146105ae578063e5160080146105cc578063f2fde38b146105df57600080fd5b8063b8f38c7414610500578063ccc7759914610520578063ce4a46a414610540578063cec4c8551461055657600080fd5b80638da5cb5b116100d15780638da5cb5b146104755780638f5c27e2146104935780639d41b9fd146104b3578063ac9650d8146104d357600080fd5b806379ba50971461040b57806383356b38146104205780638456cb59146104405780638b851b951461045557600080fd5b8063491606581161017a5780635c975abb116101495780635c975abb146103975780636a0c4ba6146103b6578063715018a6146103d657806374f040f5146103eb57600080fd5b806349160658146102f7578063519a98e01461031757806357f46a1a146103375780635c344ec91461037757600080fd5b80632fdf172b116101b65780632fdf172b1461026757806336876abb146102885780633f4ba83a146102c25780633fc8cef3146102d757600080fd5b80630c5e0546146101e85780631b5ad801146102255780631ec4aec81461024757600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50600b54610208906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023157600080fd5b506102456102403660046125b2565b6105ff565b005b34801561025357600080fd5b50600754610208906001600160a01b031681565b61027a610275366004612616565b610629565b60405190815260200161021c565b34801561029457600080fd5b506005546102a99067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161021c565b3480156102ce57600080fd5b506102456106a4565b3480156102e357600080fd5b50600354610208906001600160a01b031681565b34801561030357600080fd5b50610245610312366004612658565b6106be565b34801561032357600080fd5b5061024561033236600461270a565b6107ca565b34801561034357600080fd5b506103676103523660046125b2565b60026020526000908152604090205460ff1681565b604051901515815260200161021c565b34801561038357600080fd5b50610245610392366004612741565b610837565b3480156103a357600080fd5b50600154600160a01b900460ff16610367565b3480156103c257600080fd5b5061027a6103d1366004612616565b610844565b3480156103e257600080fd5b50610245610a31565b3480156103f757600080fd5b506102456104063660046125b2565b610a43565b34801561041757600080fd5b50610245610a6d565b34801561042c57600080fd5b5061024561043b3660046125b2565b610aec565b34801561044c57600080fd5b50610245610b16565b34801561046157600080fd5b50600a54610208906001600160a01b031681565b34801561048157600080fd5b506000546001600160a01b0316610208565b34801561049f57600080fd5b50600854610208906001600160a01b031681565b3480156104bf57600080fd5b506102456104ce3660046125b2565b610b2e565b3480156104df57600080fd5b506104f36104ee36600461275a565b610b58565b60405161021c919061281f565b34801561050c57600080fd5b5061024561051b3660046125b2565b610c4b565b34801561052c57600080fd5b5061024561053b3660046125b2565b610c75565b34801561054c57600080fd5b5061027a60045481565b34801561056257600080fd5b5061027a610571366004612883565b600660209081526000928352604080842090915290825290205481565b34801561059a57600080fd5b50600954610208906001600160a01b031681565b3480156105ba57600080fd5b506001546001600160a01b0316610208565b61027a6105da366004612616565b610c9f565b3480156105eb57600080fd5b506102456105fa3660046125b2565b610cc0565b610607610d31565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526002602052604081205460ff16610659576040516348f5c3ed60e01b815260040160405180910390fd5b6000610663610d8b565b60208101519091506001600160a01b03166106915760405163e6c4247b60e01b815260040160405180910390fd5b61069c816000610efc565b949350505050565b6106ac610d31565b6106b4611047565b6106bc611097565b565b600a60009054906101000a90046001600160a01b03166001600160a01b0316635f6970c3888888888888886040516106f79291906128af565b6040519081900381206001600160e01b031960e089901b1682526107229695949392916004016128e8565b6020604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107659190612929565b61078257604051631403112d60e21b815260040160405180910390fd5b6107c182828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110ec92505050565b50505050505050565b6107d2610d31565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915582519384529083015233917fa71618a9ed4e81ce27edc2700d38db549c32abb5e4f32ec57f791151030fbc45910160405180910390a25050565b61083f610d31565b600455565b3360009081526002602052604081205460ff16610874576040516348f5c3ed60e01b815260040160405180910390fd5b6004546001600160f01b0381169060f01c600061088f610d8b565b90506060806000602a6024356042013560f01c01803560f01c6040519450808552806002830160208701378060028301013560f01c8160208701019450808552808260048501016020870137840160208101604081905260d8870151600954630afd9fa560e31b90925294506001600160a01b031692506357ecfd28915061091d9086908690602401612946565b6020604051808303816000875af115801561093c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109609190612929565b61097c5760405162ec6f7b60e31b815260040160405180910390fd5b6000610989858730611173565b6000818152600660209081526040808320898301516001600160a01b031684529091529020549091508015806109bf5750808314155b156109dd57604051631196c86360e21b815260040160405180910390fd5b6000828152600660209081526040808320898301516001600160a01b0390811685529252822091909155600354600754610a22928992859287928e92811691166111d7565b9b9a5050505050505050505050565b610a39610d31565b6106bc60006114d6565b610a4b610d31565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60015433906001600160a01b03168114610ae05760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b610ae9816114d6565b50565b610af4610d31565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b610b1e610d31565b610b266114ef565b6106bc61153c565b610b36610d31565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6060610b62610d31565b8167ffffffffffffffff811115610b7b57610b7b612974565b604051908082528060200260200182016040528015610bae57816020015b6060815260200190600190039081610b995790505b50905060005b82811015610c4357610c1e30858584818110610bd257610bd261298a565b9050602002810190610be491906129a0565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061157f92505050565b828281518110610c3057610c3061298a565b6020908102919091010152600101610bb4565b505b92915050565b610c53610d31565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b610c7d610d31565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000610ca96114ef565b6000610cb3610d8b565b905061069c816001610efc565b610cc8610d31565b600180546001600160a01b0383166001600160a01b03199091168117909155610cf96000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000546001600160a01b031633146106bc5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ad7565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260853560f01c3560843560f81c1c42811015610e0b5763931997cf60e01b60005260046000fd5b60483560601c8252605c3560601c602083015260703560601c60408301528060608301525060883560f01c3560873560f81c1c6080820152608b3560f01c35608a3560f81c1c60a0820152608e3560f01c35608d3560f81c1c60c0820152600060d13560f81c118060e08301528060018114610ebd5760d23560f81c8061010085015260018103610eb75760d33560601c61012085015260e83560f01c3560e73560f81c1c6101408501525b50505090565b6101153560f81c8061010085015260018103610eb7576101163560601c61012085015261012b3560f01c3561012a3560f81c1c61014085015250505090565b6005805460009167ffffffffffffffff9091169082610f1a836129fd565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005546004549116915060f081901c906001600160f01b03166000610f6087876115ab565b90508660e0015115610f7657610f768782611746565b610f9f87828960a00151600014610f98576007546001600160a01b03166117bb565b60006117bb565b6040805160ec8082526101208201909252600091602082018180368337019050509050610fcd8185876118a6565b80516020820120600354610ff1908a908490869088906001600160a01b03166118d4565b965061100c610fff8a611b8b565b848b604001518a85611bd5565b60055467ffffffffffffffff87811691161461103b576040516329f745a760e01b815260040160405180910390fd5b50505050505092915050565b600154600160a01b900460ff166106bc5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ad7565b61109f611047565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60208181015160408084015160608501516000848152600686528381206001600160a01b038316825290955291842080549394919384929061112f908490612a24565b909155505060408051848152602081018490527f98e783c3864bbf744a057ef605a2a61701c3b62b5ed68b3745b99094497daf1f910160405180910390a150505050565b600060405160ec81016040528451815260208501516020820152604085015160408201526080850151606082015260a085015160808201528360f01b60a08201528260a2820152602a6024356042013560f01c60c283013760ec9020949350505050565b60008660a001518760c001516111ed9190612a24565b861461120c5760405163fe9ba5cd60e01b815260040160405180910390fd5b60a08701511561123c5761123c828860a0015189602001516001600160a01b0316611c949092919063ffffffff16565b60c08701511561143e57826001600160a01b031687602001516001600160a01b0316148015611276575060408701516001600160a01b0316155b156112ba5760c0870151611294906001600160a01b03851690611d6e565b865160c088015160208901516112b5926001600160a01b0390911691611c94565b61143e565b60208701516001600160a01b03161580156112ea5750826001600160a01b031687604001516001600160a01b0316145b156113345760c0870151611308906001600160a01b03851690611dba565b865160c08801516020890151611329926001600160a01b0390911691611c94565b5060c086015161143e565b86604001516001600160a01b031687602001516001600160a01b03160361137657865160c08801516020890151611329926001600160a01b0390911691611c94565b60208701516000906001600160a01b0316611396575060c08701516113bc565b6113bc858960c001518a602001516001600160a01b0316611dff9092919063ffffffff16565b60006113c88683611ea1565b90935090508061143b5760208901516001600160a01b0316156113ff5760208901516113ff906001600160a01b0316876000611dff565b885160c08a015160208b0151611420926001600160a01b0390911691611c94565b60208901516001600160a01b031660408a015260c089015192505b50505b86600001516001600160a01b0316336001600160a01b03167f13d672f2c19bbdf5ce8c9c4894d9586248592fd27d555c2c03ac5e49d219f45d89602001518a604001518b60a001518c60c001516114959190612a24565b604080516001600160a01b03948516815293909216602084015290820152606081018590526080810189905260a00160405180910390a39695505050505050565b600180546001600160a01b0319169055610ae981611f06565b600154600160a01b900460ff16156106bc5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610ad7565b6115446114ef565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586110cf3390565b60606115a48383604051806060016040528060278152602001612b4b60279139611f56565b9392505050565b610100820151600090819081816115c4576101406115c8565b6101805b61ffff16905060006115dc82610140612a24565b90506040519350808401604052826001811461161a577f6d270d8b96a17d623996c9fcafb1b091927d68dcaab797c0f5dd271e918c2eeb855261163e565b7f112d7d894fe0b136fbc52b80f6940fb79db28e03d78dd281e952df731f3e5ff185525b506042602435013560f090811c80358685019081526020808301359082015260408083013581830152606080840135908301526080808401359083015260a080840135851c9083015260a283013560c083015260c283013560e090811c9201918252519192909160c684013590911c908160c885018237818120602093909301928352810183820160c881013560f01c90819060ca0183378181016040529020602092909201919091525061173b90507f31da2c74f8c27ef76897147f0ad12d949a674ee71cd159480d92be28583408717fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc68987858b6002611fce565b979650505050505050565b60008060008060d13560f81c935060d235925060f23591506101133560f01c356101123560f81c1c90506117b385308861014001518960a001518a60c0015161178f9190612a24565b6117999190612a24565b60208a01516001600160a01b031692919085898989612178565b505050505050565b60a08301511561182a5760208301516001600160a01b0316611802576117fd818460a0015185602001516001600160a01b0316611c949092919063ffffffff16565b61182a565b61182a82828560a0015186602001516001600160a01b03166121cd909392919063ffffffff16565b610140830151156118735760208301516001600160a01b03166118785761187383610120015184610140015185602001516001600160a01b0316611c949092919063ffffffff16565b505050565b6118738284610120015185610140015186602001516001600160a01b03166121cd909392919063ffffffff16565b60c26024356042013560f01c602085013760f09190911b60e28301523060e483015260c01b61010490910152565b84516000906001600160a01b0316301461190157604051638aa3a72f60e01b815260040160405180910390fd5b60208601516001600160a01b0316611957578561014001518660a001518760c0015161192d9190612a24565b6119379190612a24565b341015611957576040516365719fe160e11b815260040160405180910390fd5b60208601516001600160a01b03161580156119875750816001600160a01b031686604001516001600160a01b0316145b156119b05760c08601516119a5906001600160a01b03841690611dba565b5060c0850151611b00565b816001600160a01b031686602001516001600160a01b03161480156119e0575060408601516001600160a01b0316155b15611a2657611a0d84308860c0015189602001516001600160a01b03166121cd909392919063ffffffff16565b60c08601516119a5906001600160a01b03841690611d6e565b85604001516001600160a01b031686602001516001600160a01b031603611a6f576119a584308860c0015189602001516001600160a01b03166121cd909392919063ffffffff16565b60208601516000906001600160a01b0316611a8f575060c0860151611add565b611ab785308960c001518a602001516001600160a01b03166121cd909392919063ffffffff16565b611add848860c0015189602001516001600160a01b0316611dff9092919063ffffffff16565b6000611ae98583611ea1565b909350905080611afd573d6000803e3d6000fd5b50505b85600001516001600160a01b0316846001600160a01b03167f37600fc06910ae05ad532c02a9de91251b21674999c33c6e6da90271029bfa23886020015189604001518a61014001518b60a001518c60c00151611b5d9190612a24565b611b679190612a24565b868b604051611b7a959493929190612a37565b60405180910390a395945050505050565b60208101516000906001600160a01b031615611ba75734610c45565b8161014001518260a001518360c00151611bc19190612a24565b611bcb9190612a24565b610c459034612a71565b600854611bef906001600160a01b03858116911684611dff565b60006024356042013560f01c604051915060c48201604052637c2b6edb60e11b825283600483015260c281013560e01c602483015260a2810135604483015284606483015260a2810135608483015250611c6b60008260a48460a4611c549190612a24565b6008546001600160a01b031693929190602061222c565b611c8857604051631bc5aabf60e21b815260040160405180910390fd5b6117b38683858861228e565b6001600160a01b038316611d1c576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cef576040519150601f19603f3d011682016040523d82523d6000602084013e611cf4565b606091505b5050905080611d16576040516312171d8360e31b815260040160405180910390fd5b50505050565b600060405190506044810160405263a9059cbb60e01b8152826004820152816024820152611d5184600083604460008061222c565b611d16576040516312171d8360e31b815260040160405180910390fd5b6000604051905060248101604052632e1a7d4d60e01b8152816004820152611d9d83600083602460008061222c565b6118735760405163c617296b60e01b815260040160405180910390fd5b6000604051905060048101604052630d0e30db60e41b8152611de2838383600460008061222c565b6118735760405163bdc844ed60e01b815260040160405180910390fd5b600060405190506044810160405263095ea7b360e01b8152826004820152816024820152611e3484600083604460008061222c565b611d165760006024820152611e5084600083604460008061222c565b611e6d576040516340b27c2160e11b815260040160405180910390fd5b816024820152611e8484600083604460008061222c565b611d16576040516340b27c2160e11b815260040160405180910390fd5b6000806040516024356042013560f01c60448103818301604052630563da2560e21b835260206004840152806024840152604051602081016040528160448086013760208184868a8c5af1945060018503611efb57805195505b505050509250929050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060600080856001600160a01b031685604051611f739190612a84565b600060405180830381855af49150503d8060008114611fae576040519150601f19603f3d011682016040523d82523d6000602084013e611fb3565b606091505b5091509150611fc4868383876123f3565b9695505050505050565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091528183018a9052606082018990524660808301523060a0808401919091528351808403909101815260c090920190925280519101206000906000806000803060208b01523360408b01528a5160608b015260208b015160808b015260408b015160a08b015260608b015160c08b015260808b015160e08b015260a08b01516101008b015260c08b01516101208b015260016101008c0151036120b0576101208b01516101408b01526101408b01516101608b01525b888a206040519a5060428b0160405261190160f01b8b528560028c01528060228c01525060428a209350609035925060b035915060d03560f81c905087156121315760006121008585858561246c565b9050339650806000528760205260016040600020541461212b57638baa579f60e01b60005260046000fd5b50612168565b61213d8484848461246c565b9550306001600160a01b0387160361216857604051638baa579f60e01b815260040160405180910390fd5b5050505050979650505050505050565b60405160e4810160405263d505accf60e01b81528760048201528660248201528560448201528460648201528360848201528260a48201528160c482015260008060e48360008d5af150505050505050505050565b60006040519050606481016040526323b872dd60e01b815283600482015282602482015281604482015261220885600083606460008061222c565b61222557604051631e4e7d0960e21b815260040160405180910390fd5b5050505050565b600061226f565b60003d156001811461224a57801561225b57612269565b823b1561225657600191505b612269565b60206000803e600080511191505b50919050565b81838587898b5af1612285573d6000803e3d6000fd5b61173b87612233565b604080516060808252608082019092526000916020820181803683370190505090506060806024356042013560f01c60c681013560f01c60405193508084528060c8830160208601378060c88301013560f01c8160208601019350808452808260ca85010160208601378301602090810160409081528682018a9052868101899052920135606086015250600b549051630c93e3bb60e01b81526001600160a01b0390911690630c93e3bb908990612352903090869088908a908c90600401612aa0565b6000604051808303818588803b15801561236b57600080fd5b505af115801561237f573d6000803e3d6000fd5b5050600a54604051631c92115f60e01b81526001600160a01b039091169350631c92115f92506123b89150849086908890600401612afe565b600060405180830381600087803b1580156123d257600080fd5b505af11580156123e6573d6000803e3d6000fd5b5050505050505050505050565b6060831561246257825160000361245b576001600160a01b0385163b61245b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad7565b508161069c565b61069c838361256c565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156124af57604051638baa579f60e01b815260040160405180910390fd5b8160ff16601b141580156124c757508160ff16601c14155b156124e557604051638baa579f60e01b815260040160405180910390fd5b60408051600081526020810180835287905260ff841691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612538573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661069c57604051638baa579f60e01b815260040160405180910390fd5b81511561257c5781518083602001fd5b8060405162461bcd60e51b8152600401610ad79190612b37565b80356001600160a01b03811681146125ad57600080fd5b919050565b6000602082840312156125c457600080fd5b6115a482612596565b60008083601f8401126125df57600080fd5b50813567ffffffffffffffff8111156125f757600080fd5b60208301915083602082850101111561260f57600080fd5b9250929050565b6000806020838503121561262957600080fd5b823567ffffffffffffffff81111561264057600080fd5b61264c858286016125cd565b90969095509350505050565b60008060008060008060006080888a03121561267357600080fd5b87359650602088013567ffffffffffffffff8082111561269257600080fd5b61269e8b838c016125cd565b909850965060408a01359150808211156126b757600080fd5b6126c38b838c016125cd565b909650945060608a01359150808211156126dc57600080fd5b506126e98a828b016125cd565b989b979a50959850939692959293505050565b8015158114610ae957600080fd5b6000806040838503121561271d57600080fd5b61272683612596565b91506020830135612736816126fc565b809150509250929050565b60006020828403121561275357600080fd5b5035919050565b6000806020838503121561276d57600080fd5b823567ffffffffffffffff8082111561278557600080fd5b818501915085601f83011261279957600080fd5b8135818111156127a857600080fd5b8660208260051b85010111156127bd57600080fd5b60209290920196919550909350505050565b60005b838110156127ea5781810151838201526020016127d2565b50506000910152565b6000815180845261280b8160208601602086016127cf565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561287657603f198886030184526128648583516127f3565b94509285019290850190600101612848565b5092979650505050505050565b6000806040838503121561289657600080fd5b823591506128a660208401612596565b90509250929050565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8681526080602082015260006129026080830187896128bf565b82810360408401526129158186886128bf565b915050826060830152979650505050505050565b60006020828403121561293b57600080fd5b81516115a4816126fc565b60408152600061295960408301856127f3565b828103602084015261296b81856127f3565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126129b757600080fd5b83018035915067ffffffffffffffff8211156129d257600080fd5b60200191503681900382131561260f57600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff808316818103612a1a57612a1a6129e7565b6001019392505050565b80820180821115610c4557610c456129e7565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061173b908301846127f3565b81810381811115610c4557610c456129e7565b60008251612a968184602087016127cf565b9190910192915050565b600060018060a01b03808816835260a06020840152612ac260a08401886127f3565b8381036040850152612ad481886127f3565b90508381036060850152612ae881876127f3565b9250508084166080840152509695505050505050565b606081526000612b1160608301866127f3565b8281036020840152612b2381866127f3565b90508281036040840152611fc481856127f3565b6020815260006115a460208301846127f356fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220582f8099bd84358a095763e8c54945d05827162ff7a6b596a1ac2f0e2ea7d5c564736f6c63430008180033
Deployed Bytecode
0x6080604052600436106101dc5760003560e01c806379ba509711610102578063b8f38c7411610095578063dc0b3d2111610064578063dc0b3d211461058e578063e30c3978146105ae578063e5160080146105cc578063f2fde38b146105df57600080fd5b8063b8f38c7414610500578063ccc7759914610520578063ce4a46a414610540578063cec4c8551461055657600080fd5b80638da5cb5b116100d15780638da5cb5b146104755780638f5c27e2146104935780639d41b9fd146104b3578063ac9650d8146104d357600080fd5b806379ba50971461040b57806383356b38146104205780638456cb59146104405780638b851b951461045557600080fd5b8063491606581161017a5780635c975abb116101495780635c975abb146103975780636a0c4ba6146103b6578063715018a6146103d657806374f040f5146103eb57600080fd5b806349160658146102f7578063519a98e01461031757806357f46a1a146103375780635c344ec91461037757600080fd5b80632fdf172b116101b65780632fdf172b1461026757806336876abb146102885780633f4ba83a146102c25780633fc8cef3146102d757600080fd5b80630c5e0546146101e85780631b5ad801146102255780631ec4aec81461024757600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50600b54610208906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023157600080fd5b506102456102403660046125b2565b6105ff565b005b34801561025357600080fd5b50600754610208906001600160a01b031681565b61027a610275366004612616565b610629565b60405190815260200161021c565b34801561029457600080fd5b506005546102a99067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161021c565b3480156102ce57600080fd5b506102456106a4565b3480156102e357600080fd5b50600354610208906001600160a01b031681565b34801561030357600080fd5b50610245610312366004612658565b6106be565b34801561032357600080fd5b5061024561033236600461270a565b6107ca565b34801561034357600080fd5b506103676103523660046125b2565b60026020526000908152604090205460ff1681565b604051901515815260200161021c565b34801561038357600080fd5b50610245610392366004612741565b610837565b3480156103a357600080fd5b50600154600160a01b900460ff16610367565b3480156103c257600080fd5b5061027a6103d1366004612616565b610844565b3480156103e257600080fd5b50610245610a31565b3480156103f757600080fd5b506102456104063660046125b2565b610a43565b34801561041757600080fd5b50610245610a6d565b34801561042c57600080fd5b5061024561043b3660046125b2565b610aec565b34801561044c57600080fd5b50610245610b16565b34801561046157600080fd5b50600a54610208906001600160a01b031681565b34801561048157600080fd5b506000546001600160a01b0316610208565b34801561049f57600080fd5b50600854610208906001600160a01b031681565b3480156104bf57600080fd5b506102456104ce3660046125b2565b610b2e565b3480156104df57600080fd5b506104f36104ee36600461275a565b610b58565b60405161021c919061281f565b34801561050c57600080fd5b5061024561051b3660046125b2565b610c4b565b34801561052c57600080fd5b5061024561053b3660046125b2565b610c75565b34801561054c57600080fd5b5061027a60045481565b34801561056257600080fd5b5061027a610571366004612883565b600660209081526000928352604080842090915290825290205481565b34801561059a57600080fd5b50600954610208906001600160a01b031681565b3480156105ba57600080fd5b506001546001600160a01b0316610208565b61027a6105da366004612616565b610c9f565b3480156105eb57600080fd5b506102456105fa3660046125b2565b610cc0565b610607610d31565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526002602052604081205460ff16610659576040516348f5c3ed60e01b815260040160405180910390fd5b6000610663610d8b565b60208101519091506001600160a01b03166106915760405163e6c4247b60e01b815260040160405180910390fd5b61069c816000610efc565b949350505050565b6106ac610d31565b6106b4611047565b6106bc611097565b565b600a60009054906101000a90046001600160a01b03166001600160a01b0316635f6970c3888888888888886040516106f79291906128af565b6040519081900381206001600160e01b031960e089901b1682526107229695949392916004016128e8565b6020604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107659190612929565b61078257604051631403112d60e21b815260040160405180910390fd5b6107c182828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110ec92505050565b50505050505050565b6107d2610d31565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915582519384529083015233917fa71618a9ed4e81ce27edc2700d38db549c32abb5e4f32ec57f791151030fbc45910160405180910390a25050565b61083f610d31565b600455565b3360009081526002602052604081205460ff16610874576040516348f5c3ed60e01b815260040160405180910390fd5b6004546001600160f01b0381169060f01c600061088f610d8b565b90506060806000602a6024356042013560f01c01803560f01c6040519450808552806002830160208701378060028301013560f01c8160208701019450808552808260048501016020870137840160208101604081905260d8870151600954630afd9fa560e31b90925294506001600160a01b031692506357ecfd28915061091d9086908690602401612946565b6020604051808303816000875af115801561093c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109609190612929565b61097c5760405162ec6f7b60e31b815260040160405180910390fd5b6000610989858730611173565b6000818152600660209081526040808320898301516001600160a01b031684529091529020549091508015806109bf5750808314155b156109dd57604051631196c86360e21b815260040160405180910390fd5b6000828152600660209081526040808320898301516001600160a01b0390811685529252822091909155600354600754610a22928992859287928e92811691166111d7565b9b9a5050505050505050505050565b610a39610d31565b6106bc60006114d6565b610a4b610d31565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60015433906001600160a01b03168114610ae05760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b610ae9816114d6565b50565b610af4610d31565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b610b1e610d31565b610b266114ef565b6106bc61153c565b610b36610d31565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6060610b62610d31565b8167ffffffffffffffff811115610b7b57610b7b612974565b604051908082528060200260200182016040528015610bae57816020015b6060815260200190600190039081610b995790505b50905060005b82811015610c4357610c1e30858584818110610bd257610bd261298a565b9050602002810190610be491906129a0565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061157f92505050565b828281518110610c3057610c3061298a565b6020908102919091010152600101610bb4565b505b92915050565b610c53610d31565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b610c7d610d31565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000610ca96114ef565b6000610cb3610d8b565b905061069c816001610efc565b610cc8610d31565b600180546001600160a01b0383166001600160a01b03199091168117909155610cf96000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000546001600160a01b031633146106bc5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ad7565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260853560f01c3560843560f81c1c42811015610e0b5763931997cf60e01b60005260046000fd5b60483560601c8252605c3560601c602083015260703560601c60408301528060608301525060883560f01c3560873560f81c1c6080820152608b3560f01c35608a3560f81c1c60a0820152608e3560f01c35608d3560f81c1c60c0820152600060d13560f81c118060e08301528060018114610ebd5760d23560f81c8061010085015260018103610eb75760d33560601c61012085015260e83560f01c3560e73560f81c1c6101408501525b50505090565b6101153560f81c8061010085015260018103610eb7576101163560601c61012085015261012b3560f01c3561012a3560f81c1c61014085015250505090565b6005805460009167ffffffffffffffff9091169082610f1a836129fd565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005546004549116915060f081901c906001600160f01b03166000610f6087876115ab565b90508660e0015115610f7657610f768782611746565b610f9f87828960a00151600014610f98576007546001600160a01b03166117bb565b60006117bb565b6040805160ec8082526101208201909252600091602082018180368337019050509050610fcd8185876118a6565b80516020820120600354610ff1908a908490869088906001600160a01b03166118d4565b965061100c610fff8a611b8b565b848b604001518a85611bd5565b60055467ffffffffffffffff87811691161461103b576040516329f745a760e01b815260040160405180910390fd5b50505050505092915050565b600154600160a01b900460ff166106bc5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ad7565b61109f611047565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60208181015160408084015160608501516000848152600686528381206001600160a01b038316825290955291842080549394919384929061112f908490612a24565b909155505060408051848152602081018490527f98e783c3864bbf744a057ef605a2a61701c3b62b5ed68b3745b99094497daf1f910160405180910390a150505050565b600060405160ec81016040528451815260208501516020820152604085015160408201526080850151606082015260a085015160808201528360f01b60a08201528260a2820152602a6024356042013560f01c60c283013760ec9020949350505050565b60008660a001518760c001516111ed9190612a24565b861461120c5760405163fe9ba5cd60e01b815260040160405180910390fd5b60a08701511561123c5761123c828860a0015189602001516001600160a01b0316611c949092919063ffffffff16565b60c08701511561143e57826001600160a01b031687602001516001600160a01b0316148015611276575060408701516001600160a01b0316155b156112ba5760c0870151611294906001600160a01b03851690611d6e565b865160c088015160208901516112b5926001600160a01b0390911691611c94565b61143e565b60208701516001600160a01b03161580156112ea5750826001600160a01b031687604001516001600160a01b0316145b156113345760c0870151611308906001600160a01b03851690611dba565b865160c08801516020890151611329926001600160a01b0390911691611c94565b5060c086015161143e565b86604001516001600160a01b031687602001516001600160a01b03160361137657865160c08801516020890151611329926001600160a01b0390911691611c94565b60208701516000906001600160a01b0316611396575060c08701516113bc565b6113bc858960c001518a602001516001600160a01b0316611dff9092919063ffffffff16565b60006113c88683611ea1565b90935090508061143b5760208901516001600160a01b0316156113ff5760208901516113ff906001600160a01b0316876000611dff565b885160c08a015160208b0151611420926001600160a01b0390911691611c94565b60208901516001600160a01b031660408a015260c089015192505b50505b86600001516001600160a01b0316336001600160a01b03167f13d672f2c19bbdf5ce8c9c4894d9586248592fd27d555c2c03ac5e49d219f45d89602001518a604001518b60a001518c60c001516114959190612a24565b604080516001600160a01b03948516815293909216602084015290820152606081018590526080810189905260a00160405180910390a39695505050505050565b600180546001600160a01b0319169055610ae981611f06565b600154600160a01b900460ff16156106bc5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610ad7565b6115446114ef565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586110cf3390565b60606115a48383604051806060016040528060278152602001612b4b60279139611f56565b9392505050565b610100820151600090819081816115c4576101406115c8565b6101805b61ffff16905060006115dc82610140612a24565b90506040519350808401604052826001811461161a577f6d270d8b96a17d623996c9fcafb1b091927d68dcaab797c0f5dd271e918c2eeb855261163e565b7f112d7d894fe0b136fbc52b80f6940fb79db28e03d78dd281e952df731f3e5ff185525b506042602435013560f090811c80358685019081526020808301359082015260408083013581830152606080840135908301526080808401359083015260a080840135851c9083015260a283013560c083015260c283013560e090811c9201918252519192909160c684013590911c908160c885018237818120602093909301928352810183820160c881013560f01c90819060ca0183378181016040529020602092909201919091525061173b90507f31da2c74f8c27ef76897147f0ad12d949a674ee71cd159480d92be28583408717fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc68987858b6002611fce565b979650505050505050565b60008060008060d13560f81c935060d235925060f23591506101133560f01c356101123560f81c1c90506117b385308861014001518960a001518a60c0015161178f9190612a24565b6117999190612a24565b60208a01516001600160a01b031692919085898989612178565b505050505050565b60a08301511561182a5760208301516001600160a01b0316611802576117fd818460a0015185602001516001600160a01b0316611c949092919063ffffffff16565b61182a565b61182a82828560a0015186602001516001600160a01b03166121cd909392919063ffffffff16565b610140830151156118735760208301516001600160a01b03166118785761187383610120015184610140015185602001516001600160a01b0316611c949092919063ffffffff16565b505050565b6118738284610120015185610140015186602001516001600160a01b03166121cd909392919063ffffffff16565b60c26024356042013560f01c602085013760f09190911b60e28301523060e483015260c01b61010490910152565b84516000906001600160a01b0316301461190157604051638aa3a72f60e01b815260040160405180910390fd5b60208601516001600160a01b0316611957578561014001518660a001518760c0015161192d9190612a24565b6119379190612a24565b341015611957576040516365719fe160e11b815260040160405180910390fd5b60208601516001600160a01b03161580156119875750816001600160a01b031686604001516001600160a01b0316145b156119b05760c08601516119a5906001600160a01b03841690611dba565b5060c0850151611b00565b816001600160a01b031686602001516001600160a01b03161480156119e0575060408601516001600160a01b0316155b15611a2657611a0d84308860c0015189602001516001600160a01b03166121cd909392919063ffffffff16565b60c08601516119a5906001600160a01b03841690611d6e565b85604001516001600160a01b031686602001516001600160a01b031603611a6f576119a584308860c0015189602001516001600160a01b03166121cd909392919063ffffffff16565b60208601516000906001600160a01b0316611a8f575060c0860151611add565b611ab785308960c001518a602001516001600160a01b03166121cd909392919063ffffffff16565b611add848860c0015189602001516001600160a01b0316611dff9092919063ffffffff16565b6000611ae98583611ea1565b909350905080611afd573d6000803e3d6000fd5b50505b85600001516001600160a01b0316846001600160a01b03167f37600fc06910ae05ad532c02a9de91251b21674999c33c6e6da90271029bfa23886020015189604001518a61014001518b60a001518c60c00151611b5d9190612a24565b611b679190612a24565b868b604051611b7a959493929190612a37565b60405180910390a395945050505050565b60208101516000906001600160a01b031615611ba75734610c45565b8161014001518260a001518360c00151611bc19190612a24565b611bcb9190612a24565b610c459034612a71565b600854611bef906001600160a01b03858116911684611dff565b60006024356042013560f01c604051915060c48201604052637c2b6edb60e11b825283600483015260c281013560e01c602483015260a2810135604483015284606483015260a2810135608483015250611c6b60008260a48460a4611c549190612a24565b6008546001600160a01b031693929190602061222c565b611c8857604051631bc5aabf60e21b815260040160405180910390fd5b6117b38683858861228e565b6001600160a01b038316611d1c576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cef576040519150601f19603f3d011682016040523d82523d6000602084013e611cf4565b606091505b5050905080611d16576040516312171d8360e31b815260040160405180910390fd5b50505050565b600060405190506044810160405263a9059cbb60e01b8152826004820152816024820152611d5184600083604460008061222c565b611d16576040516312171d8360e31b815260040160405180910390fd5b6000604051905060248101604052632e1a7d4d60e01b8152816004820152611d9d83600083602460008061222c565b6118735760405163c617296b60e01b815260040160405180910390fd5b6000604051905060048101604052630d0e30db60e41b8152611de2838383600460008061222c565b6118735760405163bdc844ed60e01b815260040160405180910390fd5b600060405190506044810160405263095ea7b360e01b8152826004820152816024820152611e3484600083604460008061222c565b611d165760006024820152611e5084600083604460008061222c565b611e6d576040516340b27c2160e11b815260040160405180910390fd5b816024820152611e8484600083604460008061222c565b611d16576040516340b27c2160e11b815260040160405180910390fd5b6000806040516024356042013560f01c60448103818301604052630563da2560e21b835260206004840152806024840152604051602081016040528160448086013760208184868a8c5af1945060018503611efb57805195505b505050509250929050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060600080856001600160a01b031685604051611f739190612a84565b600060405180830381855af49150503d8060008114611fae576040519150601f19603f3d011682016040523d82523d6000602084013e611fb3565b606091505b5091509150611fc4868383876123f3565b9695505050505050565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091528183018a9052606082018990524660808301523060a0808401919091528351808403909101815260c090920190925280519101206000906000806000803060208b01523360408b01528a5160608b015260208b015160808b015260408b015160a08b015260608b015160c08b015260808b015160e08b015260a08b01516101008b015260c08b01516101208b015260016101008c0151036120b0576101208b01516101408b01526101408b01516101608b01525b888a206040519a5060428b0160405261190160f01b8b528560028c01528060228c01525060428a209350609035925060b035915060d03560f81c905087156121315760006121008585858561246c565b9050339650806000528760205260016040600020541461212b57638baa579f60e01b60005260046000fd5b50612168565b61213d8484848461246c565b9550306001600160a01b0387160361216857604051638baa579f60e01b815260040160405180910390fd5b5050505050979650505050505050565b60405160e4810160405263d505accf60e01b81528760048201528660248201528560448201528460648201528360848201528260a48201528160c482015260008060e48360008d5af150505050505050505050565b60006040519050606481016040526323b872dd60e01b815283600482015282602482015281604482015261220885600083606460008061222c565b61222557604051631e4e7d0960e21b815260040160405180910390fd5b5050505050565b600061226f565b60003d156001811461224a57801561225b57612269565b823b1561225657600191505b612269565b60206000803e600080511191505b50919050565b81838587898b5af1612285573d6000803e3d6000fd5b61173b87612233565b604080516060808252608082019092526000916020820181803683370190505090506060806024356042013560f01c60c681013560f01c60405193508084528060c8830160208601378060c88301013560f01c8160208601019350808452808260ca85010160208601378301602090810160409081528682018a9052868101899052920135606086015250600b549051630c93e3bb60e01b81526001600160a01b0390911690630c93e3bb908990612352903090869088908a908c90600401612aa0565b6000604051808303818588803b15801561236b57600080fd5b505af115801561237f573d6000803e3d6000fd5b5050600a54604051631c92115f60e01b81526001600160a01b039091169350631c92115f92506123b89150849086908890600401612afe565b600060405180830381600087803b1580156123d257600080fd5b505af11580156123e6573d6000803e3d6000fd5b5050505050505050505050565b6060831561246257825160000361245b576001600160a01b0385163b61245b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad7565b508161069c565b61069c838361256c565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156124af57604051638baa579f60e01b815260040160405180910390fd5b8160ff16601b141580156124c757508160ff16601c14155b156124e557604051638baa579f60e01b815260040160405180910390fd5b60408051600081526020810180835287905260ff841691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612538573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661069c57604051638baa579f60e01b815260040160405180910390fd5b81511561257c5781518083602001fd5b8060405162461bcd60e51b8152600401610ad79190612b37565b80356001600160a01b03811681146125ad57600080fd5b919050565b6000602082840312156125c457600080fd5b6115a482612596565b60008083601f8401126125df57600080fd5b50813567ffffffffffffffff8111156125f757600080fd5b60208301915083602082850101111561260f57600080fd5b9250929050565b6000806020838503121561262957600080fd5b823567ffffffffffffffff81111561264057600080fd5b61264c858286016125cd565b90969095509350505050565b60008060008060008060006080888a03121561267357600080fd5b87359650602088013567ffffffffffffffff8082111561269257600080fd5b61269e8b838c016125cd565b909850965060408a01359150808211156126b757600080fd5b6126c38b838c016125cd565b909650945060608a01359150808211156126dc57600080fd5b506126e98a828b016125cd565b989b979a50959850939692959293505050565b8015158114610ae957600080fd5b6000806040838503121561271d57600080fd5b61272683612596565b91506020830135612736816126fc565b809150509250929050565b60006020828403121561275357600080fd5b5035919050565b6000806020838503121561276d57600080fd5b823567ffffffffffffffff8082111561278557600080fd5b818501915085601f83011261279957600080fd5b8135818111156127a857600080fd5b8660208260051b85010111156127bd57600080fd5b60209290920196919550909350505050565b60005b838110156127ea5781810151838201526020016127d2565b50506000910152565b6000815180845261280b8160208601602086016127cf565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561287657603f198886030184526128648583516127f3565b94509285019290850190600101612848565b5092979650505050505050565b6000806040838503121561289657600080fd5b823591506128a660208401612596565b90509250929050565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8681526080602082015260006129026080830187896128bf565b82810360408401526129158186886128bf565b915050826060830152979650505050505050565b60006020828403121561293b57600080fd5b81516115a4816126fc565b60408152600061295960408301856127f3565b828103602084015261296b81856127f3565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126129b757600080fd5b83018035915067ffffffffffffffff8211156129d257600080fd5b60200191503681900382131561260f57600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff808316818103612a1a57612a1a6129e7565b6001019392505050565b80820180821115610c4557610c456129e7565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061173b908301846127f3565b81810381811115610c4557610c456129e7565b60008251612a968184602087016127cf565b9190910192915050565b600060018060a01b03808816835260a06020840152612ac260a08401886127f3565b8381036040850152612ad481886127f3565b90508381036060850152612ae881876127f3565b9250508084166080840152509695505050505050565b606081526000612b1160608301866127f3565b8281036020840152612b2381866127f3565b90508281036040840152611fc481856127f3565b6020815260006115a460208301846127f356fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220582f8099bd84358a095763e8c54945d05827162ff7a6b596a1ac2f0e2ea7d5c564736f6c63430008180033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.