More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 427 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
X Bundle | 53438675 | 435 days ago | IN | 0 POL | 0.13148179 | ||||
X Bundle | 53438635 | 435 days ago | IN | 0 POL | 0.07582978 | ||||
X Bundle | 51013277 | 498 days ago | IN | 0 POL | 0.84394995 | ||||
X Bundle | 50929392 | 500 days ago | IN | 0 POL | 0.07337161 | ||||
X Bundle | 50907217 | 501 days ago | IN | 0 POL | 0.04971735 | ||||
X Bundle | 50409143 | 513 days ago | IN | 0 POL | 0.23534487 | ||||
X Bundle | 49172170 | 544 days ago | IN | 0 POL | 0.15755154 | ||||
X Bundle | 48394241 | 564 days ago | IN | 0 POL | 0.08121715 | ||||
X Bundle | 48241160 | 568 days ago | IN | 0 POL | 0.0819574 | ||||
X Bundle | 48240374 | 568 days ago | IN | 0 POL | 0.04151913 | ||||
X Bundle | 47742611 | 581 days ago | IN | 0 POL | 0.09631456 | ||||
X Bundle | 47058354 | 598 days ago | IN | 0 POL | 0.06348188 | ||||
Bump Transfer | 46630964 | 609 days ago | IN | 0.61387128 POL | 0.00672127 | ||||
X Bundle | 46630953 | 609 days ago | IN | 0 POL | 0.03159904 | ||||
X Bundle | 46454067 | 613 days ago | IN | 0 POL | 0.08505004 | ||||
Bump Transfer | 45959595 | 626 days ago | IN | 0.55920012 POL | 0.00600534 | ||||
X Bundle | 45959584 | 626 days ago | IN | 0 POL | 0.02560867 | ||||
X Bundle | 45547109 | 636 days ago | IN | 0 POL | 0.03925328 | ||||
X Bundle | 45503388 | 637 days ago | IN | 0 POL | 0.03722773 | ||||
X Bundle | 45503295 | 637 days ago | IN | 0 POL | 0.02958167 | ||||
X Bundle | 45502669 | 637 days ago | IN | 0 POL | 0.07804884 | ||||
Bump Transfer | 45342970 | 641 days ago | IN | 1.30091185 POL | 0.00819358 | ||||
X Bundle | 45342958 | 641 days ago | IN | 0 POL | 0.03990187 | ||||
Bump Transfer | 45241588 | 644 days ago | IN | 1.70743291 POL | 0.01743914 | ||||
X Bundle | 45241579 | 644 days ago | IN | 0 POL | 0.09183221 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
46630964 | 609 days ago | 0.61387128 POL | ||||
45959595 | 626 days ago | 0.55920012 POL | ||||
45342970 | 641 days ago | 1.30091185 POL | ||||
45241588 | 644 days ago | 1.70743291 POL | ||||
45233832 | 644 days ago | 0.51888873 POL | ||||
45231340 | 644 days ago | 0.00122499 POL | ||||
45182215 | 645 days ago | 0.50619651 POL | ||||
45148752 | 646 days ago | 0.49878379 POL | ||||
45147369 | 646 days ago | 0.49754281 POL | ||||
45138885 | 647 days ago | 0.49582023 POL | ||||
45073500 | 648 days ago | 2.67282297 POL | ||||
45071997 | 648 days ago | 0.00115637 POL | ||||
45066629 | 648 days ago | 0.47862928 POL | ||||
45061474 | 648 days ago | 1.11646819 POL | ||||
45032541 | 649 days ago | 0.00123724 POL | ||||
45024993 | 649 days ago | 0.50468743 POL | ||||
45021886 | 649 days ago | 0.52458859 POL | ||||
45011551 | 650 days ago | 0.53170531 POL | ||||
45006930 | 650 days ago | 1.53108119 POL | ||||
44997440 | 650 days ago | 5 POL | ||||
44996230 | 650 days ago | 0.52617033 POL | ||||
44962984 | 651 days ago | 1.71861532 POL | ||||
44962899 | 651 days ago | 1.52427771 POL | ||||
44962659 | 651 days ago | 0.5162461 POL | ||||
44960655 | 651 days ago | 2.02522431 POL |
Loading...
Loading
Contract Name:
ConnextRouter
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title ConnextRouter * * @author Fujidao Labs * * @notice A Router implementing Connext specific bridging logic. */ import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {IConnext, IXReceiver} from "../interfaces/connext/IConnext.sol"; import {ConnextHandler} from "./ConnextHandler.sol"; import {BaseRouter} from "../abstracts/BaseRouter.sol"; import {IWETH9} from "../abstracts/WETH9.sol"; import {IVault} from "../interfaces/IVault.sol"; import {IVaultPermissions} from "../interfaces/IVaultPermissions.sol"; import {IChief} from "../interfaces/IChief.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import {IFlasher} from "../interfaces/IFlasher.sol"; import {LibBytes} from "../libraries/LibBytes.sol"; contract ConnextRouter is BaseRouter, IXReceiver { /** * @dev Emitted when a new destination router gets added. * * @param router the router on another chain * @param domain the destination domain identifier according Connext nomenclature */ event NewRouterAdded(address indexed router, uint256 indexed domain); /** * @dev Emitted when Connext `xCall` is invoked. * * @param transferId the unique identifier of the crosschain transfer * @param caller the account that called the function * @param receiver the router on destDomain * @param destDomain the destination domain identifier according Connext nomenclature * @param asset the asset being transferred * @param amount the amount of transferring asset the recipient address receives * @param callData the calldata sent to destination router that will get decoded and executed */ event XCalled( bytes32 indexed transferId, address indexed caller, address indexed receiver, uint256 destDomain, address asset, uint256 amount, bytes callData ); /** * @dev Emitted when the router receives a cross-chain call. * * @param transferId the unique identifier of the crosschain transfer * @param originDomain the origin domain identifier according Connext nomenclature * @param success whether or not the xBundle call succeeds * @param asset the asset being transferred * @param amount the amount of transferring asset the recipient address receives * @param callData the calldata that will get decoded and executed */ event XReceived( bytes32 indexed transferId, uint256 indexed originDomain, bool success, address asset, uint256 amount, bytes callData ); /// @dev Custom Errors error ConnextRouter__setRouter_invalidInput(); error ConnextRouter__xReceive_notReceivedAssetBalance(); error ConnextRouter__xReceive_notAllowedCaller(); error ConnextRouter__xReceiver_noValueTransferUseXbundle(); error ConnnextRouter__xBundleConnext_notSelfCalled(); /// @dev The connext contract on the origin domain. IConnext public immutable connext; ConnextHandler public immutable handler; /** * @notice A mapping of a domain of another chain and a deployed router there. * * @dev For the list of domains supported by Connext, * plz check: https://docs.connext.network/resources/deployments */ mapping(uint256 => address) public routerByDomain; modifier onlySelf() { if (msg.sender != address(this)) { revert ConnnextRouter__xBundleConnext_notSelfCalled(); } _; } constructor(IWETH9 weth, IConnext connext_, IChief chief) BaseRouter(weth, chief) { connext = connext_; handler = new ConnextHandler(address(this)); _allowCaller(msg.sender, true); } /*//////////////////////////////////// Connext specific functions ////////////////////////////////////*/ /** * @notice Called by Connext on the destination chain. * * @param transferId the unique identifier of the crosschain transfer * @param amount the amount of transferring asset, after slippage, the recipient address receives * @param asset the asset being transferred * @param originSender the address of the contract or EOA that called xcall on the origin chain * @param originDomain the origin domain identifier according Connext nomenclature * @param callData the calldata that will get decoded and executed, see "Requirements" * * @dev It does not perform authentication of the calling address. As a result of that, * all txns go through Connext's fast path. * If `xBundle` fails internally, this contract will send the received funds to {ConnextHandler}. * * Requirements: * - `calldata` parameter must be encoded with the following structure: * > abi.encode(Action[] actions, bytes[] args) * - actions: array of serialized actions to execute from available enum {IRouter.Action}. * - args: array of encoded arguments according to each action. See {BaseRouter-internalBundle}. */ function xReceive( bytes32 transferId, uint256 amount, address asset, address originSender, uint32 originDomain, bytes memory callData ) external returns (bytes memory) { (Action[] memory actions, bytes[] memory args) = abi.decode(callData, (Action[], bytes[])); uint256 balance; uint256 beforeSlipped; if (amount > 0) { // Ensure that at this entry point expected `asset` `amount` is received. balance = IERC20(asset).balanceOf(address(this)); if (balance < amount) { revert ConnextRouter__xReceive_notReceivedAssetBalance(); } else { _tempTokenToCheck = Snapshot(asset, balance - amount); } /** * @dev Due to the AMM nature of Connext, there could be some slippage * incurred on the amount that this contract receives after bridging. * There is also a routing fee of 0.05% of the bridged amount. * The slippage can't be calculated upfront so that's why we need to * replace `amount` in the encoded args for the first action if * the action is Deposit, or Payback. */ (args[0], beforeSlipped) = _accountForSlippage(amount, actions[0], args[0]); } /** * @dev Connext will keep the custody of the bridged amount if the call * to `xReceive` fails. That's why we need to ensure the funds are not stuck at Connext. * Therefore we try/catch instead of directly calling _bundleInternal(...). */ try this.xBundleConnext(actions, args, beforeSlipped) { emit XReceived(transferId, originDomain, true, asset, amount, callData); } catch { if (balance > 0) { SafeERC20.safeTransfer(IERC20(asset), address(handler), balance); handler.recordFailed(transferId, amount, asset, originSender, originDomain, actions, args); } // Ensure clear storage for token balance checks. delete _tempTokenToCheck; emit XReceived(transferId, originDomain, false, asset, amount, callData); } return ""; } /** * @notice Function selector created to allow try-catch procedure in Connext message data * passing.Including argument for `beforeSlipepd` not available in {BaseRouter-xBundle}. * * @param actions an array of actions that will be executed in a row * @param args an array of encoded inputs needed to execute each action * @param beforeSlipped amount passed by the origin cross-chain router operation * * @dev Requirements: * - Must only be called within the context of this same contract. */ function xBundleConnext( Action[] calldata actions, bytes[] calldata args, uint256 beforeSlipped ) external payable onlySelf { _bundleInternal(actions, args, beforeSlipped); } /** * @dev Decodes and replaces "amount" argument in args with `receivedAmount` * in Deposit, or Payback. * * Refer to: * https://github.com/Fujicracy/fuji-v2/issues/253#issuecomment-1385995095 */ function _accountForSlippage( uint256 receivedAmount, Action action, bytes memory args ) internal pure returns (bytes memory newArgs, uint256 beforeSlipped) { newArgs = args; // Check first action type and replace with slippage-amount. if (action == Action.Deposit || action == Action.Payback) { // For Deposit or Payback. (IVault vault, uint256 amount, address receiver, address sender) = abi.decode(args, (IVault, uint256, address, address)); if (amount != receivedAmount) { beforeSlipped = amount; newArgs = abi.encode(vault, receivedAmount, receiver, sender); } } else if (action == Action.WithdrawETH) { // For WithdrawETH (uint256 amount, address receiver) = abi.decode(args, (uint256, address)); if (amount != receivedAmount) { beforeSlipped = amount; newArgs = abi.encode(receivedAmount, receiver); } } } /// @inheritdoc BaseRouter function _crossTransfer( bytes memory params, address beneficiary ) internal override returns (address) { ( uint256 destDomain, uint256 slippage, address asset, uint256 amount, address receiver, address sender ) = abi.decode(params, (uint256, uint256, address, uint256, address, address)); address beneficiary_ = _checkBeneficiary(beneficiary, receiver); _safePullTokenFrom(asset, sender, amount); _safeApprove(asset, address(connext), amount); bytes32 transferId = connext.xcall( // _destination: Domain ID of the destination chain uint32(destDomain), // _to: address of the target contract receiver, // _asset: address of the token contract asset, // _delegate: address that has rights to update the original slippage tolerance // by calling Connext's forceUpdateSlippage function beneficiary_, // _amount: amount of tokens to transfer amount, // _slippage: can be anything between 0-10000 becaus // the maximum amount of slippage the user will accept in BPS, 30 == 0.3% slippage, // _callData: empty because we're only sending funds "" ); emit XCalled(transferId, msg.sender, receiver, destDomain, asset, amount, ""); return beneficiary_; } /// @inheritdoc BaseRouter function _crossTransferWithCalldata( bytes memory params, address beneficiary ) internal override returns (address beneficiary_) { ( uint256 destDomain, uint256 slippage, address asset, uint256 amount, address sender, bytes memory callData ) = abi.decode(params, (uint256, uint256, address, uint256, address, bytes)); (Action[] memory actions, bytes[] memory args,) = abi.decode(callData, (Action[], bytes[], uint256)); beneficiary_ = _checkBeneficiary(beneficiary, _getBeneficiaryFromCalldata(actions, args)); _safePullTokenFrom(asset, sender, amount); _safeApprove(asset, address(connext), amount); bytes32 transferId = connext.xcall( // _destination: Domain ID of the destination chain uint32(destDomain), // _to: address of the target contract routerByDomain[destDomain], // _asset: address of the token contract asset, // _delegate: address that can revert or forceLocal on destination beneficiary_, // _amount: amount of tokens to transfer amount, // _slippage: can be anything between 0-10000 becaus // the maximum amount of slippage the user will accept in BPS, 30 == 0.3% slippage, // _callData: the encoded calldata to send callData ); emit XCalled( transferId, msg.sender, routerByDomain[destDomain], destDomain, asset, amount, callData ); return beneficiary_; } /** * @dev Returns who is the first receiver of value in `callData` * Requirements: * - Must revert if "swap" is first action * * @param actions to execute in {BaseRouter-xBundle} * @param args to execute in {BaseRouter-xBundle} */ function _getBeneficiaryFromCalldata( Action[] memory actions, bytes[] memory args ) internal view override returns (address beneficiary_) { if (actions[0] == Action.Deposit || actions[0] == Action.Payback) { // For Deposit or Payback. (,, address receiver,) = abi.decode(args[0], (IVault, uint256, address, address)); beneficiary_ = receiver; } else if (actions[0] == Action.Withdraw || actions[0] == Action.Borrow) { // For Withdraw or Borrow (,,, address owner) = abi.decode(args[0], (IVault, uint256, address, address)); beneficiary_ = owner; } else if (actions[0] == Action.WithdrawETH) { // For WithdrawEth (, address receiver) = abi.decode(args[0], (uint256, address)); beneficiary_ = receiver; } else if (actions[0] == Action.PermitBorrow || actions[0] == Action.PermitWithdraw) { (, address owner,,,,,,) = abi.decode( args[0], (IVaultPermissions, address, address, uint256, uint256, uint8, bytes32, bytes32) ); beneficiary_ = owner; } else if (actions[0] == Action.Flashloan) { (,,,, bytes memory requestorCalldata) = abi.decode(args[0], (IFlasher, address, uint256, address, bytes)); (Action[] memory newActions, bytes[] memory newArgs) = abi.decode( LibBytes.slice(requestorCalldata, 4, requestorCalldata.length - 4), (Action[], bytes[]) ); beneficiary_ = _getBeneficiaryFromCalldata(newActions, newArgs); } else if (actions[0] == Action.XTransfer) { (,,,, address receiver,) = abi.decode(args[0], (uint256, uint256, address, uint256, address, address)); beneficiary_ = receiver; } else if (actions[0] == Action.XTransferWithCall) { (,,,, bytes memory callData) = abi.decode(args[0], (uint256, uint256, address, uint256, bytes)); (Action[] memory actions_, bytes[] memory args_,) = abi.decode(callData, (Action[], bytes[], uint256)); beneficiary_ = _getBeneficiaryFromCalldata(actions_, args_); } else if (actions[0] == Action.DepositETH) { /// @dev There is no beneficiary in depositETH, therefore we do a recurssion with i = 1 uint256 len = actions.length; Action[] memory chopActions = new Action[](len -1); bytes[] memory chopArgs = new bytes[](len -1); for (uint256 i = 1; i < len;) { chopActions[i - 1] = actions[i]; chopArgs[i - 1] = args[i]; unchecked { ++i; } } beneficiary_ = _getBeneficiaryFromCalldata(chopActions, chopArgs); } else if (actions[0] == Action.Swap) { /// @dev swap cannot be actions[0]. revert BaseRouter__bundleInternal_swapNotFirstAction(); } } /** * @notice Anyone can call this function on the origin domain to increase the relayer fee for a transfer. * * @param transferId the unique identifier of the crosschain transaction */ function bumpTransfer(bytes32 transferId) external payable { connext.bumpTransfer{value: msg.value}(transferId); } /** * @notice Registers an address of this contract deployed on another chain. * * @param domain unique identifier of a chain as defined in * https://docs.connext.network/resources/deployments * @param router address of a router deployed on the chain defined by its domain * * @dev The mapping domain -> router is used in `xReceive` to verify the origin sender. * Requirements: * - Must be restricted to timelock. * - `router` must be a non-zero address. */ function setRouter(uint256 domain, address router) external onlyTimelock { if (router == address(0)) { revert ConnextRouter__setRouter_invalidInput(); } routerByDomain[domain] = router; emit NewRouterAdded(router, domain); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IConnext * * @author Fujidao Labs * * @notice Defines the common interfaces and data types used * to interact with Connext Amarok. */ /** * @notice These are the parameters that will remain constant between the * two chains. They are supplied on `xcall` and should be asserted on `execute` * @property to - The account that receives funds, in the event of a crosschain call, * will receive funds if the call fails. * * @param originDomain - The originating domain (i.e. where `xcall` is called). Must match nomad domain schema * @param destinationDomain - The final domain (i.e. where `execute` / `reconcile` are called). Must match nomad domain schema * @param canonicalDomain - The canonical domain of the asset you are bridging * @param to - The address you are sending funds (and potentially data) to * @param delegate - An address who can execute txs on behalf of `to`, in addition to allowing relayers * @param receiveLocal - If true, will use the local nomad asset on the destination instead of adopted. * @param callData - The data to execute on the receiving chain. If no crosschain call is needed, then leave empty. * @param slippage - Slippage user is willing to accept from original amount in expressed in BPS (i.e. if * a user takes 1% slippage, this is expressed as 1_000) * @param originSender - The msg.sender of the xcall * @param bridgedAmt - The amount sent over the bridge (after potential AMM on xcall) * @param normalizedIn - The amount sent to `xcall`, normalized to 18 decimals * @param nonce - The nonce on the origin domain used to ensure the transferIds are unique * @param canonicalId - The unique identifier of the canonical token corresponding to bridge assets */ struct TransferInfo { uint32 originDomain; uint32 destinationDomain; uint32 canonicalDomain; address to; address delegate; bool receiveLocal; bytes callData; uint256 slippage; address originSender; uint256 bridgedAmt; uint256 normalizedIn; uint256 nonce; bytes32 canonicalId; } /** * @notice * @param params - The TransferInfo. These are consistent across sending and receiving chains. * @param routers - The routers who you are sending the funds on behalf of. * @param routerSignatures - Signatures belonging to the routers indicating permission to use funds * for the signed transfer ID. * @param sequencer - The sequencer who assigned the router path to this transfer. * @param sequencerSignature - Signature produced by the sequencer for path assignment accountability * for the path that was signed. */ struct ExecuteArgs { TransferInfo params; address[] routers; bytes[] routerSignatures; address sequencer; bytes sequencerSignature; } interface IConnext { function xcall( uint32 _destination, address _to, address _asset, address _delegate, uint256 _amount, uint256 _slippage, bytes calldata _callData ) external payable returns (bytes32); function execute(ExecuteArgs calldata _args) external returns (bool success, bytes memory returnData); function bumpTransfer(bytes32 transferId) external payable; function forceUpdateSlippage(TransferInfo calldata _params, uint256 _slippage) external; } interface IXReceiver { function xReceive( bytes32 _transferId, uint256 _amount, address _asset, address _originSender, uint32 _origin, bytes memory _callData ) external returns (bytes memory); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title ConnextHandler * * @author Fujidao Labs * * @notice Handles failed transactions from Connext and keeps custody of * the transferred funds. */ import {ConnextRouter} from "./ConnextRouter.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import {IVault} from "../interfaces/IVault.sol"; import {ISwapper} from "../interfaces/ISwapper.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; contract ConnextHandler { /** * @dev Contains the information of a failed transaction. */ struct FailedTxn { bytes32 transferId; uint256 amount; address asset; address originSender; uint32 originDomain; IRouter.Action[] actions; bytes[] args; uint128 nonce; bool executed; } /** * @dev Emitted when a failed transaction is recorded. * * @param transferId unique id of the cross-chain txn * @param amount transferred * @param asset being transferred * @param originSender of the cross-chain txn * @param originDomain of the cross-chain txn * @param actions to be called in xBundle * @param args to be called for each action in xBundle * @param nonce of failed txn */ event FailedTxnRecorded( bytes32 indexed transferId, uint256 amount, address asset, address originSender, uint32 originDomain, IRouter.Action[] actions, bytes[] args, uint128 nonce ); /** * @dev Emitted when a failed transaction gets retried. * * @param transferId the unique identifier of the cross-chain txn * @param success boolean * @param oldArgs of the failed transaction * @param newArgs attemped in execution */ event FailedTxnExecuted( bytes32 indexed transferId, IRouter.Action[] oldActions, IRouter.Action[] newActions, bytes[] oldArgs, bytes[] newArgs, uint128 nonce, bool indexed success ); /// @dev Custom errors error ConnextHandler__callerNotConnextRouter(); error ConnextHandler__executeFailed_emptyTxn(); error ConnextHandler__executeFailed_tranferAlreadyExecuted(bytes32 transferId, uint128 nonce); bytes32 private constant ZERO_BYTES32 = 0x0000000000000000000000000000000000000000000000000000000000000000; ConnextRouter public immutable connextRouter; /** * @dev Maps a failed transferId -> nonce -> calldata * Multiple failed attempts are registered with nonce */ mapping(bytes32 => mapping(uint256 => FailedTxn)) private _failedTxns; modifier onlyConnextRouter() { if (msg.sender != address(connextRouter)) { revert ConnextHandler__callerNotConnextRouter(); } _; } /// @dev Modifier that checks `msg.sender` is an allowed called in {ConnextRouter}. modifier onlyAllowedCaller() { if (!connextRouter.isAllowedCaller(msg.sender)) { revert ConnextHandler__callerNotConnextRouter(); } _; } /** * @notice Constructor that initialized */ constructor(address connextRouter_) { connextRouter = ConnextRouter(payable(connextRouter_)); } /** * @notice Returns the struct of failed transaction by `transferId`. * * @param transferId the unique identifier of the cross-chain txn * @param nonce attempt of failed tx */ function getFailedTxn(bytes32 transferId, uint128 nonce) public view returns (FailedTxn memory) { return _failedTxns[transferId][nonce]; } function getFailedTxnNextNonce(bytes32 transferId) public view returns (uint128 next) { next = 0; for (uint256 i; i < type(uint8).max;) { if (!isTransferIdRecorded(transferId, uint128(i))) { next = uint128(i); break; } unchecked { ++i; } } } /** * @notice Returns the true if the failed transaction is already recorded. * * @param transferId the unique identifier of the cross-chain txn */ function isTransferIdRecorded(bytes32 transferId, uint128 nonce) public view returns (bool) { FailedTxn memory ftxn = _failedTxns[transferId][nonce]; if (ftxn.transferId != ZERO_BYTES32 && ftxn.originDomain != 0) { return true; } else { return false; } } /** * @notice Records a failed {ConnextRouter-xReceive} call. * * @param transferId the unique identifier of the cross-chain txn * @param amount the amount of transferring asset, after slippage, the recipient address receives * @param asset the asset being transferred * @param originSender the address of the contract or EOA that called xcall on the origin chain * @param originDomain the origin domain identifier according Connext nomenclature * @param actions that should be executed in {BaseRouter-internalBundle} * @param args for the actions * * @dev At this point of execution {ConnextRouter} sent all balance of `asset` to this contract. * It has already been verified that `amount` of `asset` is >= to balance sent. * This function does not need to emit an event since {ConnextRouter} already emit * a failed `XReceived` event. */ function recordFailed( bytes32 transferId, uint256 amount, address asset, address originSender, uint32 originDomain, IRouter.Action[] memory actions, bytes[] memory args ) external onlyConnextRouter { uint128 nextNonce = getFailedTxnNextNonce(transferId); _failedTxns[transferId][nextNonce] = FailedTxn( transferId, amount, asset, originSender, originDomain, actions, args, nextNonce, false ); emit FailedTxnRecorded( transferId, amount, asset, originSender, originDomain, actions, args, nextNonce ); } /** * @notice Executes a failed transaction with update `args` * * @param transferId the unique identifier of the cross-chain txn * @param nonce of the failed attempt to execute * @param actions that will replace actions of failed txn * @param args taht will replace args of failed txn * * @dev Requirements: * - Must only be called by an allowed caller in {ConnextRouter}. * - Must clear the txn from `_failedTxns` mapping if execution succeeds. * - Must replace `sender` in `args` for value tranfer type actions (Deposit-Payback-Swap}. */ function executeFailedWithUpdatedArgs( bytes32 transferId, uint128 nonce, IRouter.Action[] memory actions, bytes[] memory args ) external onlyAllowedCaller { FailedTxn memory txn = _failedTxns[transferId][nonce]; if (txn.transferId == ZERO_BYTES32 || txn.originDomain == 0) { revert ConnextHandler__executeFailed_emptyTxn(); } else if (txn.executed) { revert ConnextHandler__executeFailed_tranferAlreadyExecuted(transferId, nonce); } IERC20(txn.asset).approve(address(connextRouter), txn.amount); try connextRouter.xBundle(actions, args) { txn.executed = true; _failedTxns[transferId][nonce] = txn; emit FailedTxnExecuted(transferId, txn.actions, actions, txn.args, args, nonce, true); } catch { emit FailedTxnExecuted(transferId, txn.actions, actions, txn.args, args, nonce, false); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; /** * @title BaseRouter * * @author Fujidao Labs * * @notice Abstract contract to be inherited by all routers. */ import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import {ISwapper} from "../interfaces/ISwapper.sol"; import {IVault} from "../interfaces/IVault.sol"; import {IChief} from "../interfaces/IChief.sol"; import {IFlasher} from "../interfaces/IFlasher.sol"; import {IVaultPermissions} from "../interfaces/IVaultPermissions.sol"; import {SystemAccessControl} from "../access/SystemAccessControl.sol"; import {IWETH9} from "../abstracts/WETH9.sol"; import {LibBytes} from "../libraries/LibBytes.sol"; abstract contract BaseRouter is SystemAccessControl, IRouter { /** * @dev Contains an address of an ERC-20 and the balance the router holds * at a given moment of the transaction (ref. `_tokensToCheck`). */ struct Snapshot { address token; uint256 balance; } /** * @dev Struct used internally containing the arguments of a IRouter.Action.Permit* to store * and pass in memory and avoid "stack too deep" errors. */ struct PermitArgs { IVaultPermissions vault; address owner; address receiver; uint256 amount; uint256 deadline; uint8 v; bytes32 r; bytes32 s; } /** * @dev Emitted when `caller` is updated according to `allowed` boolean * to perform cross-chain calls. * * @param caller permitted for cross-chain calls * @param allowed boolean state */ event AllowCaller(address caller, bool allowed); /// @dev Custom Errors error BaseRouter__bundleInternal_swapNotFirstAction(); error BaseRouter__bundleInternal_paramsMismatch(); error BaseRouter__bundleInternal_flashloanInvalidRequestor(); error BaseRouter__bundleInternal_noBalanceChange(); error BaseRouter__bundleInternal_insufficientETH(); error BaseRouter__bundleInternal_notBeneficiary(); error BaseRouter__checkVaultInput_notActiveVault(); error BaseRouter__bundleInternal_notAllowedSwapper(); error BaseRouter__bundleInternal_notAllowedFlasher(); error BaseRouter__handlePermit_notPermitAction(); error BaseRouter__safeTransferETH_transferFailed(); error BaseRouter__receive_senderNotWETH(); error BaseRouter__fallback_notAllowed(); error BaseRouter__allowCaller_zeroAddress(); error BaseRouter__allowCaller_noAllowChange(); error BaseRouter__bundleInternal_insufficientFlashloanBalance(); IWETH9 public immutable WETH9; bytes32 private constant ZERO_BYTES32 = 0x0000000000000000000000000000000000000000000000000000000000000000; /// @dev Apply it on entry cross-chain calls functions as required. mapping(address => bool) public isAllowedCaller; /** * @dev Stores token balances of this contract at a given moment. * It's used to pass tokens to check from parent contract this contract. */ Snapshot internal _tempTokenToCheck; /** * @notice Constructor of a new {BaseRouter}. * * @param weth wrapped native token of this chain * @param chief contract */ constructor(IWETH9 weth, IChief chief) payable SystemAccessControl(address(chief)) { WETH9 = weth; } /// @inheritdoc IRouter function xBundle(Action[] calldata actions, bytes[] calldata args) external payable override { _bundleInternal(actions, args, 0); } /** * @notice Marks a specific caller as allowed/disallowed to call certain functions. * * @param caller address to allow/disallow * @param allowed 'true' to allow, 'false' to disallow * * @dev The authorization is to be implemented on the bridge-specific contract. */ function allowCaller(address caller, bool allowed) external onlyTimelock { _allowCaller(caller, allowed); } /// @inheritdoc IRouter function sweepToken(ERC20 token, address receiver) external onlyHouseKeeper { SafeERC20.safeTransfer(token, receiver, token.balanceOf(address(this))); } /// @inheritdoc IRouter function sweepETH(address receiver) external onlyHouseKeeper { _safeTransferETH(receiver, address(this).balance); } /** * @dev Executes a bundle of actions. * Requirements: * - Must not leave any balance in this contract after all actions. * - Must call `_checkNoBalanceChange()` after all `actions` are executed. * - Must call `_addTokenToList()` in `actions` that involve tokens. * - Must clear `_beneficiary` from storage after all `actions` are executed. * * @param actions an array of actions that will be executed in a row * @param args an array of encoded inputs needed to execute each action * @param beforeSlipped amount passed by the origin cross-chain router operation */ function _bundleInternal( Action[] memory actions, bytes[] memory args, uint256 beforeSlipped ) internal { uint256 len = actions.length; if (len != args.length) { revert BaseRouter__bundleInternal_paramsMismatch(); } /** * @dev Operations in the bundle should "benefit" or be executed * on behalf of this account. These are receivers on DEPOSIT and PAYBACK * or owners on WITHDRAW and BORROW. */ address beneficiary; /** * @dev Hash generated during execution of "_bundleInternal()" that should * match the signed permit. * This argument is used in {VaultPermissions-PermitWithdraw} and * {VaultPermissions-PermitBorrow} */ bytes32 actionArgsHash; /** * @dev Stores token balances of this contract at a given moment. * It's used to ensure there're no changes in balances at the * end of a transaction. */ Snapshot[] memory tokensToCheck = new Snapshot[](10); /// @dev Add token to check from parent calls. if (_tempTokenToCheck.token != address(0)) { tokensToCheck[0] = _tempTokenToCheck; } uint256 nativeBalance = address(this).balance - msg.value; for (uint256 i; i < len;) { Action action = actions[i]; if (action == Action.Deposit) { // DEPOSIT (IVault vault, uint256 amount, address receiver, address sender) = abi.decode(args[i], (IVault, uint256, address, address)); _checkVaultInput(address(vault)); address token = vault.asset(); beneficiary = _checkBeneficiary(beneficiary, receiver); tokensToCheck = _addTokenToList(token, tokensToCheck); _safePullTokenFrom(token, sender, amount); _safeApprove(token, address(vault), amount); vault.deposit(amount, receiver); } else if (action == Action.Withdraw) { // WITHDRAW (IVault vault, uint256 amount, address receiver, address owner) = abi.decode(args[i], (IVault, uint256, address, address)); _checkVaultInput(address(vault)); beneficiary = _checkBeneficiary(beneficiary, owner); tokensToCheck = _addTokenToList(vault.asset(), tokensToCheck); vault.withdraw(amount, receiver, owner); } else if (action == Action.Borrow) { // BORROW (IVault vault, uint256 amount, address receiver, address owner) = abi.decode(args[i], (IVault, uint256, address, address)); _checkVaultInput(address(vault)); beneficiary = _checkBeneficiary(beneficiary, owner); tokensToCheck = _addTokenToList(vault.debtAsset(), tokensToCheck); vault.borrow(amount, receiver, owner); } else if (action == Action.Payback) { // PAYBACK (IVault vault, uint256 amount, address receiver, address sender) = abi.decode(args[i], (IVault, uint256, address, address)); _checkVaultInput(address(vault)); address token = vault.debtAsset(); beneficiary = _checkBeneficiary(beneficiary, receiver); tokensToCheck = _addTokenToList(token, tokensToCheck); _safePullTokenFrom(token, sender, amount); _safeApprove(token, address(vault), amount); vault.payback(amount, receiver); } else if (action == Action.PermitWithdraw) { // PERMIT WITHDRAW if (actionArgsHash == ZERO_BYTES32) { actionArgsHash = _getActionArgsHash(actions, args, beforeSlipped); } // Scoped code in new private function to avoid "Stack too deep" address owner_ = _handlePermitAction(action, args[i], actionArgsHash); beneficiary = _checkBeneficiary(beneficiary, owner_); } else if (action == Action.PermitBorrow) { // PERMIT BORROW if (actionArgsHash == ZERO_BYTES32) { actionArgsHash = _getActionArgsHash(actions, args, beforeSlipped); } // Scoped code in new private function to avoid "Stack too deep" address owner_ = _handlePermitAction(action, args[i], actionArgsHash); beneficiary = _checkBeneficiary(beneficiary, owner_); } else if (action == Action.XTransfer) { // SIMPLE BRIDGE TRANSFER beneficiary = _crossTransfer(args[i], beneficiary); } else if (action == Action.XTransferWithCall) { // BRIDGE WITH CALLDATA beneficiary = _crossTransferWithCalldata(args[i], beneficiary); } else if (action == Action.Swap) { // SWAP if (i == 0) { /// @dev swap cannot be actions[0]. revert BaseRouter__bundleInternal_swapNotFirstAction(); } (beneficiary, tokensToCheck) = _handleSwapAction(args[i], beneficiary, tokensToCheck); } else if (action == Action.Flashloan) { // FLASHLOAN // Decode params. ( IFlasher flasher, address asset, uint256 flashAmount, address requestor, bytes memory requestorCalldata ) = abi.decode(args[i], (IFlasher, address, uint256, address, bytes)); if (!chief.allowedFlasher(address(flasher))) { revert BaseRouter__bundleInternal_notAllowedFlasher(); } if (requestor != address(this)) { revert BaseRouter__bundleInternal_flashloanInvalidRequestor(); } tokensToCheck = _addTokenToList(asset, tokensToCheck); (Action[] memory innerActions, bytes[] memory innerArgs) = abi.decode( LibBytes.slice(requestorCalldata, 4, requestorCalldata.length - 4), (Action[], bytes[]) ); beneficiary = _getBeneficiaryFromCalldata(innerActions, innerArgs); // Call Flasher. flasher.initiateFlashloan(asset, flashAmount, requestor, requestorCalldata); } else if (action == Action.DepositETH) { uint256 amount = abi.decode(args[i], (uint256)); if (amount != msg.value) { revert BaseRouter__bundleInternal_insufficientETH(); } tokensToCheck = _addTokenToList(address(WETH9), tokensToCheck); WETH9.deposit{value: msg.value}(); } else if (action == Action.WithdrawETH) { (uint256 amount, address receiver) = abi.decode(args[i], (uint256, address)); beneficiary = _checkBeneficiary(beneficiary, receiver); tokensToCheck = _addTokenToList(address(WETH9), tokensToCheck); WETH9.withdraw(amount); _safeTransferETH(receiver, amount); } unchecked { ++i; } } _checkNoBalanceChange(tokensToCheck, nativeBalance); } /** * @dev Handles both permit actions logic flow. * This function was required to avoid "stack too deep" error in `_bundleInternal()`. * * @param action either IRouter.Action.PermitWithdraw (6), or IRouter.Action.PermitBorrow (7) * @param arg of the ongoing action * @param actionArgsHash_ created previously withing `_bundleInternal()` to be used in permit check */ function _handlePermitAction( IRouter.Action action, bytes memory arg, bytes32 actionArgsHash_ ) private returns (address) { PermitArgs memory permitArgs; { ( permitArgs.vault, permitArgs.owner, permitArgs.receiver, permitArgs.amount, permitArgs.deadline, permitArgs.v, permitArgs.r, permitArgs.s ) = abi.decode( arg, (IVaultPermissions, address, address, uint256, uint256, uint8, bytes32, bytes32) ); } _checkVaultInput(address(permitArgs.vault)); if (action == IRouter.Action.PermitWithdraw) { permitArgs.vault.permitWithdraw( permitArgs.owner, permitArgs.receiver, permitArgs.amount, permitArgs.deadline, actionArgsHash_, permitArgs.v, permitArgs.r, permitArgs.s ); } else if (action == IRouter.Action.PermitBorrow) { permitArgs.vault.permitBorrow( permitArgs.owner, permitArgs.receiver, permitArgs.amount, permitArgs.deadline, actionArgsHash_, permitArgs.v, permitArgs.r, permitArgs.s ); } else { revert BaseRouter__handlePermit_notPermitAction(); } return permitArgs.owner; } /** * @dev Returns the `zeroPermitEncodedArgs` which is required to create * the `actionArgsHash` used during permit signature * * @param vault that will execute action * @param owner owner of the assets * @param receiver of the assets after action * @param amount of assets being permitted in action */ function _getZeroPermitEncodedArgs( IVaultPermissions vault, address owner, address receiver, uint256 amount ) private pure returns (bytes memory) { return abi.encode(vault, owner, receiver, amount, 0, 0, ZERO_BYTES32, ZERO_BYTES32); } /** * @dev Returns the `actionsArgsHash` required in * {VaultPermissions-permitWithdraw} or {VaultPermissions-permitBorrow}. * Requirements: * - Must replace arguments in IRouter.Action.PermitWithdraw for "zeroPermit". * - Must replace arguments in IRouter.Action.PermitBorrow for "zeroPermit". * - Must replace `beforeSlipped` amount in cross-chain txs that had slippage. * * * @param actions being executed in this `_bundleInternal` * @param args provided in `_bundleInternal` * @param beforeSlipped amount passed by the origin cross-chain router operation */ function _getActionArgsHash( IRouter.Action[] memory actions, bytes[] memory args, uint256 beforeSlipped ) private pure returns (bytes32) { uint256 len = actions.length; /** * @dev We intend to ONLY modify the new bytes array. * "memory" in solidity persists within internal calls. */ bytes[] memory modArgs = new bytes[](len); for (uint256 i; i < len; i++) { modArgs[i] = args[i]; if ( i == 0 && beforeSlipped != 0 && (actions[i] == IRouter.Action.Deposit || actions[i] == IRouter.Action.Payback) ) { /** * @dev Replace slippage values in the first ( i==0 ) "value" transfer * action in the destination chain (deposit or to payback). * If `beforeSlipped` == 0, it means there was no slippage in the attempted cross-chain tx * or the tx is single chain; thereore, not requiring any replacement. * Then, if beforeSlipped != 0 and beforeSlipped != slippedAmount, function should replace * to obtain the "original" intended transfer value signed in `actionArgsHash`. */ (IVault vault, uint256 slippedAmount, address receiver, address sender) = abi.decode(modArgs[i], (IVault, uint256, address, address)); if (beforeSlipped != slippedAmount) { modArgs[i] = abi.encode(vault, beforeSlipped, receiver, sender); } } if (actions[i] == IRouter.Action.PermitWithdraw || actions[i] == IRouter.Action.PermitBorrow) { // Need to replace permit `args` at `index` with the `zeroPermitArg`. (IVaultPermissions vault, address owner, address receiver, uint256 amount,,,,) = abi.decode( modArgs[i], (IVaultPermissions, address, address, uint256, uint256, uint8, bytes32, bytes32) ); modArgs[i] = _getZeroPermitEncodedArgs(vault, owner, receiver, amount); } } return keccak256(abi.encode(actions, modArgs)); } /** * @dev Handles swap actions logic flow. * This function was required to avoid "stack too deep" error in `_bundleInternal()`. * Requirements: * - Must return updated "beneficiary" and "tokensToCheck". * * @param arg of the ongoing action * @param beneficiary_ passed through `_bundleInternal()` * @param tokensToCheck_ passed through `_bundleInternal()` */ function _handleSwapAction( bytes memory arg, address beneficiary_, Snapshot[] memory tokensToCheck_ ) internal returns (address, Snapshot[] memory) { ( ISwapper swapper, address assetIn, address assetOut, uint256 amountIn, uint256 amountOut, address receiver, address sweeper, uint256 minSweepOut ) = abi.decode(arg, (ISwapper, address, address, uint256, uint256, address, address, uint256)); if (!chief.allowedSwapper(address(swapper))) { revert BaseRouter__bundleInternal_notAllowedSwapper(); } tokensToCheck_ = _addTokenToList(assetIn, tokensToCheck_); tokensToCheck_ = _addTokenToList(assetOut, tokensToCheck_); _safeApprove(assetIn, address(swapper), amountIn); if (receiver != address(this) && !chief.allowedFlasher(receiver)) { beneficiary_ = _checkBeneficiary(beneficiary_, receiver); } if (sweeper != address(this)) { beneficiary_ = _checkBeneficiary(beneficiary_, sweeper); } swapper.swap(assetIn, assetOut, amountIn, amountOut, receiver, sweeper, minSweepOut); return (beneficiary_, tokensToCheck_); } /** * @dev Helper function to transfer ETH. * * @param receiver address to receive the ETH * @param amount amount to be transferred */ function _safeTransferETH(address receiver, uint256 amount) internal { (bool success,) = receiver.call{value: amount}(new bytes(0)); if (!success) { revert BaseRouter__safeTransferETH_transferFailed(); } } /** * @dev Helper function to pull ERC-20 token from a sender address after some checks. * The checks are needed because when we bundle multiple actions * it can happen the router already holds the assets in question; * for. example when we withdraw from a vault and deposit to another one. * * @param token ERC-20 token address * @param sender address to pull tokens from * @param amount amount of tokens to be pulled */ function _safePullTokenFrom(address token, address sender, uint256 amount) internal { if (sender != address(this) && sender == msg.sender) { SafeERC20.safeTransferFrom(ERC20(token), sender, address(this), amount); } } /** * @dev Helper function to approve ERC-20 transfers. * * @param token ERC-20 address to approve * @param to address to approve as a spender * @param amount amount to be approved */ function _safeApprove(address token, address to, uint256 amount) internal { SafeERC20.safeApprove(ERC20(token), to, amount); } /** * @dev Check `allowCaller()` above. * * @param caller address to allow/disallow * @param allowed 'true' to allow, 'false' to disallow */ function _allowCaller(address caller, bool allowed) internal { if (caller == address(0)) { revert BaseRouter__allowCaller_zeroAddress(); } if (isAllowedCaller[caller] == allowed) { revert BaseRouter__allowCaller_noAllowChange(); } isAllowedCaller[caller] = allowed; emit AllowCaller(caller, allowed); } /** * @dev Function to be implemented on the bridge-specific contract * used to transfer funds WITHOUT calldata to a destination chain. */ function _crossTransfer(bytes memory, address beneficiary) internal virtual returns (address); /** * @dev Function to be implemented on the bridge-specific contract * used to transfer funds WITH calldata to a destination chain. */ function _crossTransferWithCalldata( bytes memory, address beneficiary ) internal virtual returns (address); /** * @dev Returns "true" and on what `index` if token has already * been added to `tokenList`. * * @param token address of ERC-20 to check * @param tokenList to check */ function _isInTokenList( address token, Snapshot[] memory tokenList ) private pure returns (bool value, uint256 index) { uint256 len = tokenList.length; for (uint256 i; i < len;) { if (token == tokenList[i].token) { value = true; index = i; break; } unchecked { ++i; } } } /** * @dev Adds a token and balance to a Snapshot and returns it. * Requirements: * - Must check if token has already been added. * * @param token address of ERC-20 to be pushed * @param tokenList to add token */ function _addTokenToList( address token, Snapshot[] memory tokenList ) private view returns (Snapshot[] memory) { (bool isInList, uint256 index) = _isInTokenList(token, tokenList); if (!isInList) { uint256 position = index == 0 ? index : index + 1; tokenList[position] = Snapshot(token, IERC20(token).balanceOf(address(this))); } return tokenList; } /** * @dev Checks that `erc20-balanceOf` of `_tokensToCheck` haven't change for this address. * Requirements: * - Must be called in `_bundleInternal()` at the end of all executed `actions`. * - Must clear `_tokensToCheck` from storage at the end of checks. * * @param tokensToCheck array of 'Snapshot' elements * @param nativeBalance the stored balance of ETH */ function _checkNoBalanceChange( Snapshot[] memory tokensToCheck, uint256 nativeBalance ) private view { uint256 len = tokensToCheck.length; for (uint256 i; i < len;) { if (tokensToCheck[i].token != address(0)) { uint256 previousBalance = tokensToCheck[i].balance; uint256 currentBalance = IERC20(tokensToCheck[i].token).balanceOf(address(this)); if (currentBalance != previousBalance) { revert BaseRouter__bundleInternal_noBalanceChange(); } } unchecked { ++i; } } // Check at the end the native balance. if (nativeBalance != address(this).balance) { revert BaseRouter__bundleInternal_noBalanceChange(); } } /** * @dev When bundling multiple actions assure that we act for a single beneficiary; * receivers on DEPOSIT and PAYBACK and owners on WITHDRAW and BORROW * must be the same user * * @param user address to verify is the beneficiary */ function _checkBeneficiary(address beneficiary, address user) internal pure returns (address) { if (beneficiary == address(0)) { return user; } else if (beneficiary != user) { revert BaseRouter__bundleInternal_notBeneficiary(); } else { return user; } } /** * @dev Extracts the beneficiary from a set of actions and args. * Requirements: * - Must be implemented in child contract, and added to `_crossTransfer` and * `crossTansferWithCalldata` when applicable. * * @param actions an array of actions that will be executed in a row * @param args an array of encoded inputs needed to execute each action */ function _getBeneficiaryFromCalldata( Action[] memory actions, bytes[] memory args ) internal view virtual returns (address beneficiary_); function _checkVaultInput(address vault_) internal view { if (!chief.isVaultActive(vault_)) { revert BaseRouter__checkVaultInput_notActiveVault(); } } /** * @dev Only WETH contract is allowed to transfer ETH to this address. * Prevent other addresses to send Ether to this contract. */ receive() external payable { if (msg.sender != address(WETH9)) { revert BaseRouter__receive_senderNotWETH(); } } /** * @dev Revert fallback calls. */ fallback() external payable { revert BaseRouter__fallback_notAllowed(); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IWETH9 * * @author Unknown * * @notice Abstract contract of add-on functions of a * typical ERC20 wrapped native token. */ import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; abstract contract IWETH9 is ERC20 { /// @notice Deposit ether to get wrapped ether function deposit() external payable virtual; /// @notice Withdraw wrapped ether to get ether function withdraw(uint256) external virtual; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IVault * * @author Fujidao Labs * * @notice Defines the interface for vaults extending from IERC4326. */ import {IERC4626} from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol"; import {ILendingProvider} from "./ILendingProvider.sol"; import {IFujiOracle} from "./IFujiOracle.sol"; interface IVault is IERC4626 { /** * @dev Emit when borrow action occurs. * * @param sender who calls {IVault-borrow} * @param receiver of the borrowed 'debt' amount * @param owner who will incur the debt * @param debt amount * @param shares amount of 'debtShares' received */ event Borrow( address indexed sender, address indexed receiver, address indexed owner, uint256 debt, uint256 shares ); /** * @dev Emit when payback action occurs. * * @param sender address who calls {IVault-payback} * @param owner address whose debt will be reduced * @param debt amount * @param shares amound of 'debtShares' burned */ event Payback(address indexed sender, address indexed owner, uint256 debt, uint256 shares); /** * @dev Emit when the vault is initialized * * @param initializer of this vault * */ event VaultInitialized(address initializer); /** * @dev Emit when the oracle address is changed. * * @param newOracle the new oracle address */ event OracleChanged(IFujiOracle newOracle); /** * @dev Emit when the available providers for the vault change. * * @param newProviders the new providers available */ event ProvidersChanged(ILendingProvider[] newProviders); /** * @dev Emit when the active provider is changed. * * @param newActiveProvider the new active provider */ event ActiveProviderChanged(ILendingProvider newActiveProvider); /** * @dev Emit when the vault is rebalanced. * * @param assets amount to be rebalanced * @param debt amount to be rebalanced * @param from provider * @param to provider */ event VaultRebalance(uint256 assets, uint256 debt, address indexed from, address indexed to); /** * @dev Emit when the max LTV is changed. * See factors: https://github.com/Fujicracy/CrossFuji/tree/main/packages/protocol#readme. * * @param newMaxLtv the new max LTV */ event MaxLtvChanged(uint256 newMaxLtv); /** * @dev Emit when the liquidation ratio is changed. * See factors: https://github.com/Fujicracy/CrossFuji/tree/main/packages/protocol#readme. * * @param newLiqRatio the new liquidation ratio */ event LiqRatioChanged(uint256 newLiqRatio); /** * @dev Emit when the minumum amount is changed. * * @param newMinAmount the new minimum amount */ event MinAmountChanged(uint256 newMinAmount); /** * @dev Emit when the deposit cap is changed. * * @param newDepositCap the new deposit cap of this vault */ event DepositCapChanged(uint256 newDepositCap); /*/////////////////////////// Asset management functions //////////////////////////*/ /** * @notice Returns the amount of assets owned by `owner`. * * @param owner to check balance * * @dev This method avoids having to do external conversions from shares to * assets, since {IERC4626-balanceOf} returns shares. */ function balanceOfAsset(address owner) external view returns (uint256 assets); /*/////////////////////////// Debt management functions //////////////////////////*/ /** * @notice Returns the decimals for 'debtAsset' of this vault. * * @dev Requirements: * - Must match the 'debtAsset' decimals in ERC20 token. * - Must return zero in a {YieldVault}. */ function debtDecimals() external view returns (uint8); /** * @notice Returns the address of the underlying token used as debt in functions * `borrow()`, and `payback()`. Based on {IERC4626-asset}. * * @dev Requirements: * - Must be an ERC-20 token contract. * - Must not revert. * - Must return zero in a {YieldVault}. */ function debtAsset() external view returns (address); /** * @notice Returns the amount of debt owned by `owner`. * * @param owner to check balance */ function balanceOfDebt(address owner) external view returns (uint256 debt); /** * @notice Returns the amount of `debtShares` owned by `owner`. * * @param owner to check balance */ function balanceOfDebtShares(address owner) external view returns (uint256 debtShares); /** * @notice Returns the total amount of the underlying debt asset * that is “managed” by this vault. Based on {IERC4626-totalAssets}. * * @dev Requirements: * - Must account for any compounding occuring from yield or interest accrual. * - Must be inclusive of any fees that are charged against assets in the Vault. * - Must not revert. * - Must return zero in a {YieldVault}. */ function totalDebt() external view returns (uint256); /** * @notice Returns the amount of shares this vault would exchange for the amount * of debt assets provided. Based on {IERC4626-convertToShares}. * * @param debt to convert into `debtShares` * * @dev Requirements: * - Must not be inclusive of any fees that are charged against assets in the Vault. * - Must not show any variations depending on the caller. * - Must not reflect slippage or other on-chain conditions, when performing the actual exchange. * - Must not revert. * * NOTE: This calculation MAY not reflect the “per-user” price-per-share, and instead Must reflect the * “average-user’s” price-per-share, meaning what the average user Must expect to see when exchanging to and * from. */ function convertDebtToShares(uint256 debt) external view returns (uint256 shares); /** * @notice Returns the amount of debt assets that this vault would exchange for the amount * of shares provided. Based on {IERC4626-convertToAssets}. * * @param shares amount to convert into `debt` * * @dev Requirements: * - Must not be inclusive of any fees that are charged against assets in the Vault. * - Must not show any variations depending on the caller. * - Must not reflect slippage or other on-chain conditions, when performing the actual exchange. * - Must not revert. * * NOTE: This calculation MAY not reflect the “per-user” price-per-share, and instead must reflect the * “average-user’s” price-per-share, meaning what the average user Must expect to see when exchanging to and * from. */ function convertToDebt(uint256 shares) external view returns (uint256 debt); /** * @notice Returns the maximum amount of the debt asset that can be borrowed for the `owner`, * through a borrow call. * * @param owner to check * * @dev Requirements: * - Must return a limited value if receiver is subject to some borrow limit. * - Must return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be borrowed. * - Must not revert. */ function maxBorrow(address owner) external view returns (uint256 debt); /** * @notice Returns the maximum amount of debt that can be payback by the `borrower`. * * @param owner to check * * @dev Requirements: * - Must not revert. */ function maxPayback(address owner) external view returns (uint256 debt); /** * @notice Returns the maximum amount of debt shares that can be "minted-for-borrowing" by the `borrower`. * * @param owner to check * * @dev Requirements: * - Must not revert. */ function maxMintDebt(address owner) external view returns (uint256 shares); /** * @notice Returns the maximum amount of debt shares that can be "burned-for-payback" by the `borrower`. * * @param owner to check * * @dev Requirements: * - Must not revert. */ function maxBurnDebt(address owner) external view returns (uint256 shares); /** * @notice Returns the amount of `debtShares` that borrowing `debt` amount will generate. * * @param debt amount to check * * @dev Requirements: * - Must not revert. */ function previewBorrow(uint256 debt) external view returns (uint256 shares); /** * @notice Returns the amount of debt that borrowing `debtShares` amount will generate. * * @param shares of debt to check * * @dev Requirements: * - Must not revert. */ function previewMintDebt(uint256 shares) external view returns (uint256 debt); /** * @notice Returns the amount of `debtShares` that will be burned by paying back * `debt` amount. * * @param debt to check * * @dev Requirements: * - Must not revert. */ function previewPayback(uint256 debt) external view returns (uint256 shares); /** * @notice Returns the amount of debt asset that will be pulled from user, if `debtShares` are * burned to payback. * * @param debt to check * * @dev Requirements: * - Must not revert. */ function previewBurnDebt(uint256 shares) external view returns (uint256 debt); /** * @notice Perform a borrow action. Function inspired on {IERC4626-deposit}. * * @param debt amount * @param receiver of the `debt` amount * @param owner who will incur the `debt` amount * * * @dev Mints debtShares to owner by taking a loan of exact amount of underlying tokens. * Requirements: * - Must emit the Borrow event. * - Must revert if owner does not own sufficient collateral to back debt. * - Must revert if caller is not owner or permissioned operator to act on owner behalf. */ function borrow(uint256 debt, address receiver, address owner) external returns (uint256 shares); /** * @notice Perform a borrow action by minting `debtShares`. * * @param shares of debt to mint * @param receiver of the borrowed amount * @param owner who will incur the `debt` and whom `debtShares` will be accounted * * * @dev Mints `debtShares` to `owner`. * Requirements: * - Must emit the Borrow event. * - Must revert if owner does not own sufficient collateral to back debt. * - Must revert if caller is not owner or permissioned operator to act on owner behalf. */ function mintDebt( uint256 shares, address receiver, address owner ) external returns (uint256 debt); /** * @notice Burns `debtShares` to `receiver` by paying back loan with exact amount of underlying tokens. * * @param debt amount to payback * @param receiver to whom debt amount is being paid back * * @dev Implementations will require pre-erc20-approval of the underlying debt token. * Requirements: * - Must emit a Payback event. */ function payback(uint256 debt, address receiver) external returns (uint256 shares); /** * @notice Burns `debtShares` to `owner` by paying back loan by specifying debt shares. * * @param shares of debt to payback * @param owner to whom debt amount is being paid back * * @dev Implementations will require pre-erc20-approval of the underlying debt token. * Requirements: * - Must emit a Payback event. */ function burnDebt(uint256 shares, address owner) external returns (uint256 debt); /*/////////////////// General functions ///////////////////*/ /** * @notice Returns the active provider of this vault. */ function getProviders() external view returns (ILendingProvider[] memory); /** * @notice Returns the active provider of this vault. */ function activeProvider() external view returns (ILendingProvider); /*///////////////////////// Rebalancing Function ////////////////////////*/ /** * @notice Performs rebalancing of vault by moving funds across providers. * * @param assets amount of this vault to be rebalanced * @param debt amount of this vault to be rebalanced (Note: pass zero if this is a {YieldVault}) * @param from provider * @param to provider * @param fee expected from rebalancing operation * @param setToAsActiveProvider boolean * * @dev Requirements: * - Must check providers `from` and `to` are valid. * - Must be called from a {RebalancerManager} contract that makes all proper checks. * - Must revert if caller is not an approved rebalancer. * - Must emit the VaultRebalance event. * - Must check `fee` is a reasonable amount. */ function rebalance( uint256 assets, uint256 debt, ILendingProvider from, ILendingProvider to, uint256 fee, bool setToAsActiveProvider ) external returns (bool); /*///////////////////////// Liquidation Functions /////////////////////////*/ /** * @notice Returns the current health factor of 'owner'. * * @param owner to get health factor * * @dev Requirements: * - Must return type(uint254).max when 'owner' has no debt. * - Must revert in {YieldVault}. * * 'healthFactor' is scaled up by 1e18. A value below 1e18 means 'owner' is eligable for liquidation. * See factors: https://github.com/Fujicracy/CrossFuji/tree/main/packages/protocol#readme. */ function getHealthFactor(address owner) external returns (uint256 healthFactor); /** * @notice Returns the liquidation close factor based on 'owner's' health factor. * * @param owner of debt position * * @dev Requirements: * - Must return zero if `owner` is not liquidatable. * - Must revert in {YieldVault}. */ function getLiquidationFactor(address owner) external returns (uint256 liquidationFactor); /** * @notice Performs liquidation of an unhealthy position, meaning a 'healthFactor' below 100. * * @param owner to be liquidated * @param receiver of the collateral shares of liquidation * * @dev Requirements: * - Must revert if caller is not an approved liquidator. * - Must revert if 'owner' is not liquidatable. * - Must emit the Liquidation event. * - Must liquidate 50% of 'owner' debt when: 100 >= 'healthFactor' > 95. * - Must liquidate 100% of 'owner' debt when: 95 > 'healthFactor'. * - Must revert in {YieldVault}. * * WARNING! It is liquidator's responsability to check if liquidation is profitable. */ function liquidate(address owner, address receiver) external returns (uint256 gainedShares); /*///////////////////// Setter functions ////////////////////*/ /** * @notice Sets the lists of providers of this vault. * * @param providers address array * * @dev Requirements: * - Must not contain zero addresses. */ function setProviders(ILendingProvider[] memory providers) external; /** * @notice Sets the active provider for this vault. * * @param activeProvider address * * @dev Requirements: * - Must be a provider previously set by `setProviders()`. * - Must be called from a timelock contract. * * WARNING! Changing active provider without a `rebalance()` call * can result in denial of service for vault users. */ function setActiveProvider(ILendingProvider activeProvider) external; /** * @notice Sets the minimum amount for: `deposit()`, `mint()` and borrow()`. * * @param amount to be as minimum. */ function setMinAmount(uint256 amount) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IVaultPermissions * * @author Fujidao Labs * * @notice Defines the interface for a vault extended with * signed permit operations for `withdraw()` and `borrow()` allowance. */ interface IVaultPermissions { /** * @dev Emitted when `asset` withdraw allowance is set. * * @param owner who provides allowance * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance * @param amount of allowance given */ event WithdrawApproval(address indexed owner, address operator, address receiver, uint256 amount); /** * @dev Emitted when `debtAsset` borrow allowance is set. * * @param owner who provides allowance * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance * @param amount of allowance given */ event BorrowApproval(address indexed owner, address operator, address receiver, uint256 amount); /// @dev Based on {IERC20Permit-DOMAIN_SEPARATOR}. // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external returns (bytes32); /** * @notice Returns the current amount of withdraw allowance from `owner` to `receiver` that * can be executed by `operator`. This is similar to {IERC20-allowance} for BaseVault assets, * instead of token-shares. * * @param owner who provides allowance * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance * * @dev Requirements: * - Must replace {IERC4626-allowance} in a vault implementation. */ function withdrawAllowance( address owner, address operator, address receiver ) external view returns (uint256); /** * @notice Returns the current amount of borrow allowance from `owner` to `receiver` that * can be executed by `operator`. This is similar to {IERC20-allowance} for * BaseVault-debtAsset. * * @param owner who provides allowance * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance */ function borrowAllowance( address owner, address operator, address receiver ) external view returns (uint256); /** * @dev Atomically increases the `withdrawAllowance` granted to `receiver` and * executable by `operator` by the caller. Based on OZ {ERC20-increaseAllowance} for assets. * * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance * @param byAmount to increase withdraw allowance * * @dev Requirements: * - Must emit a {WithdrawApproval} event indicating the updated withdraw allowance. * - Must check `operator` and `receiver are not zero address. */ function increaseWithdrawAllowance( address operator, address receiver, uint256 byAmount ) external returns (bool); /** * @dev Atomically decreases the `withdrawAllowance` granted to `receiver` and * executable by `operator` by the caller. Based on OZ {ERC20-decreaseAllowance} for assets. * * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance * @param byAmount to decrease withdraw allowance * * @dev Requirements: * - Must emit a {WithdrawApproval} event indicating the updated withdraw allowance. * - Must check `operator` and `receiver` are not zero address. * - Must check `operator` and `receiver` have `borrowAllowance` of at least `byAmount`. * */ function decreaseWithdrawAllowance( address operator, address receiver, uint256 byAmount ) external returns (bool); /** * @dev Atomically increases the `borrowAllowance` granted to `receiver` and * executable by `operator` by the caller. Based on OZ {ERC20-increaseAllowance} * for `debtAsset`. * * @param operator address who can execute the use of the allowance * @param receiver address who can spend the allowance * @param byAmount to increase borrow allowance * * @dev Requirements: * - Must emit a {BorrowApproval} event indicating the updated borrow allowance. * - Must check `operator` and `receiver` are not zero address. */ function increaseBorrowAllowance( address operator, address receiver, uint256 byAmount ) external returns (bool); /** * @dev Atomically decrease the `borrowAllowance` granted to `receiver` and * executable by `operator` by the caller. Based on OZ {ERC20-decreaseAllowance} * for `debtAsset`. * * @param operator who can execute the use of the allowance * @param receiver who can spend the allowance * @param byAmount to decrease borrow allowance * * Requirements: * - Must emit a {BorrowApproval} event indicating the updated borrow allowance. * - Must check `operator` and `receiver` are not the zero address. * - Must check `operator` and `receiver` have `borrowAllowance` of at least `byAmount`. */ function decreaseBorrowAllowance( address operator, address receiver, uint256 byAmount ) external returns (bool); /** * @notice Returns the curent used nonces for permits of `owner`. * Based on OZ {IERC20Permit-nonces}. * * @param owner address to check nonces */ function nonces(address owner) external view returns (uint256); /** * @notice Sets `amount` as the `withdrawAllowance` of `receiver` executable by * caller over `owner`'s tokens, given the `owner`'s signed approval. * Inspired by {IERC20Permit-permit} for assets. * * @param owner providing allowance * @param receiver who can spend the allowance * @param amount of allowance * @param deadline timestamp limit for the execution of signed permit * @param actionArgsHash keccak256 of the abi.encoded(args,actions) to be performed in {BaseRouter._internalBundle} * @param v signature value * @param r signature value * @param s signature value * * @dev Requirements: * - Must check `deadline` is a timestamp in the future. * - Must check `receiver` is a non-zero address. * - Must check that `v`, `r` and `s` are valid `secp256k1` signature for `owner` * over EIP712-formatted function arguments. * - Must check the signature used `owner`'s current nonce (see {nonces}). * - Must emits an {AssetsApproval} event. */ function permitWithdraw( address owner, address receiver, uint256 amount, uint256 deadline, bytes32 actionArgsHash, uint8 v, bytes32 r, bytes32 s ) external; /** * @notice Sets `amount` as the `borrowAllowance` of `receiver` executable by caller over * `owner`'s borrowing powwer, given the `owner`'s signed approval. * Inspired by {IERC20Permit-permit} for debt. * * @param owner address providing allowance * @param receiver address who can spend the allowance * @param amount of allowance * @param deadline timestamp limit for the execution of signed permit * @param actionArgsHash keccak256 of the abi.encoded(args,actions) to be performed in {BaseRouter._internalBundle} * @param v signature value * @param r signature value * @param s signature value * * @dev Requirements: * - Must emit a {BorrowApproval} event. * - Must be implemented in a {BorrowingVault}. * - Must check `deadline` is a timestamp in the future. * - Must check `receiver` is a non-zero address. * - Must check that `v`, `r` and `s` are valid `secp256k1` signature for `owner`. * over EIP712-formatted function arguments. * - Must check the signature used `owner`'s current nonce (see {nonces}). */ function permitBorrow( address owner, address receiver, uint256 amount, uint256 deadline, bytes32 actionArgsHash, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IChief * * @author Fujidao Labs * * @notice Defines interface for {Chief} access control operations. */ import {IAccessControl} from "openzeppelin-contracts/contracts/access/IAccessControl.sol"; interface IChief is IAccessControl { /// @notice Returns the timelock address of the FujiV2 system. function timelock() external view returns (address); /// @notice Returns the address mapper contract address of the FujiV2 system. function addrMapper() external view returns (address); /** * @notice Returns true if `vault` is active. * * @param vault to check status */ function isVaultActive(address vault) external view returns (bool); /** * @notice Returns true if `flasher` is an allowed {IFlasher}. * * @param flasher address to check */ function allowedFlasher(address flasher) external view returns (bool); /** * @notice Returns true if `swapper` is an allowed {ISwapper}. * * @param swapper address to check */ function allowedSwapper(address swapper) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title Router Interface * * @author Fujidao Labs * * @notice Define the interface for router operations. */ import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; interface IRouter { /// @dev List of actions allowed to be executed by the router. enum Action { Deposit, Withdraw, Borrow, Payback, Flashloan, Swap, PermitWithdraw, PermitBorrow, XTransfer, XTransferWithCall, DepositETH, WithdrawETH } /** * @notice An entry-point function that executes encoded commands along with provided inputs. * * @param actions an array of actions that will be executed in a row * @param args an array of encoded inputs needed to execute each action */ function xBundle(Action[] memory actions, bytes[] memory args) external payable; /** * @notice Sweeps accidental ERC-20 transfers to this contract or stuck funds due to failed * cross-chain calls (cf. ConnextRouter). * * @param token the address of the ERC-20 token to sweep * @param receiver the address that will receive the swept funds */ function sweepToken(ERC20 token, address receiver) external; /** * @notice Sweeps accidental ETH transfers to this contract. * * @param receiver the address that will receive the swept funds */ function sweepETH(address receiver) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IFlasher * @author Fujidao Labs * @notice Defines the interface for all flashloan providers. */ interface IFlasher { /** * @notice Initiates a flashloan a this provider. * @param asset address to be flashloaned. * @param amount of `asset` to be flashloaned. * @param requestor address to which flashloan will be facilitated. * @param requestorCalldata encoded args with selector that will be OPCODE-CALL'ed to `requestor`. * @dev To encode `params` see examples: * • solidity: * > abi.encodeWithSelector(contract.transferFrom.selector, from, to, amount); * • ethersJS: * > contract.interface.encodeFunctionData("transferFrom", [from, to, amount]); * • foundry cast: * > cast calldata "transferFrom(address,address,uint256)" from, to, amount * * Requirements: * - MUST implement `_checkAndSetEntryPoint()` */ function initiateFlashloan( address asset, uint256 amount, address requestor, bytes memory requestorCalldata ) external; /** * @notice Returns the address from which flashloan for `asset` is sourced. * @param asset intended to be flashloaned. * @dev Override at flashloan provider implementation as required. * Some protocol implementations source flashloans from different contracts * depending on `asset`. */ function getFlashloanSourceAddr(address asset) external view returns (address callAddr); /** * @notice Returns the expected flashloan fee for `amount` * of this flashloan provider. * @param asset to be flashloaned * @param amount of flashloan */ function computeFlashloanFee(address asset, uint256 amount) external view returns (uint256 fee); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /* * @title LibBytes * @author Gonçalo Sá <[email protected]> * * @notice Utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays * both in memory and storage. Taken from: * https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol. */ library LibBytes { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { /** * @dev Get a location of some free memory and store it in tempBytes as * Solidity does for memory variables. */ tempBytes := mload(0x40) /** * @dev Store the length of the first bytes array at the beginning of * the memory for tempBytes. */ let length := mload(_preBytes) mstore(tempBytes, length) /** * @dev Maintain a memory counter for the current write location in the * temp bytes array by adding the 32 bytes for the array length to * the starting location. */ let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes at a time. mstore(mc, mload(cc)) } /** * @dev Add the length of _postBytes to the current length of tempBytes * and store it as the new length in the first 32 bytes of the * tempBytes memory. */ length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } /** * @dev Update the free-memory pointer by padding our last write location * to 32 bytes: add 31 bytes to the end of tempBytes to move to the * next 32 byte block, then round down to the nearest multiple of * 32. If the sum of the length of the two arrays is zero then add * one before rounding down to leave a blank 32 bytes (the length block with 0). */ mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), // Round down to the nearest 32 bytes. not(31) ) ) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { /** * @dev Read the first 32 bytes of _preBytes storage, which is the length * of the array. (We don't need to use the offset into the slot * because arrays use the entire slot.) */ let fslot := sload(_preBytes.slot) /** * @dev Arrays of 31 bytes or less have an even value in their slot, * while longer arrays have an odd value. The actual length is * the slot divided by two for odd values, and the lowest order * byte divided by two for even values. * If the slot is even, bitwise and the slot with 255 and divide by * two to get the length. If the slot is odd, bitwise and the slot * with -1 and divide by two. */ let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) /** * @dev // slength can contain both the length and contents of the array * if length < 32 bytes so let's prepare for that * v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage */ switch add(lt(slength, 32), lt(newlength, 32)) case 2 { /** * @dev Since the new array still fits in the slot, we just need to * update the contents of the slot. * uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length */ sstore( _preBytes.slot, // All the modifications to the slot are inside this next block add( // we can just add to the slot contents because the bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory. mload(add(_postBytes, 0x20)), // Zero all bytes to the right. exp(0x100, sub(32, mlength)) ), // Now shift left the number of bytes to leave space for the length in the slot. exp(0x100, sub(32, newlength)) ), // Increase length by the double of the memory bytes length. mul(mlength, 2) ) ) ) } case 1 { /** * @dev The stored value fits in the slot, but the combined value * will exceed it. Get the keccak hash to get the contents of the array. */ mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // Save new length. sstore(_preBytes.slot, add(mul(newlength, 2), 1)) /** * @dev The contents of the _postBytes array start 32 bytes into * the structure. Our first read should obtain the `submod` * bytes that can fit into the unused space in the last word * of the stored array. To get this, we read 32 bytes starting * from `submod`, so the data we read overlaps with the array * contents by `submod` bytes. Masking the lowest-order * `submod` bytes allows us to add that value directly to the * stored value. */ let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // Get the keccak hash to get the contents of the array. mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // Save new length. sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as Solidity does for memory variables. tempBytes := mload(0x40) /** * @dev The first word of the slice result is potentially a partial * word read from the original array. To read it, we calculate * the length of that partial word and start copying that many * bytes into the array. The first word we copy will start with * data we don't care about, but the last `lengthmod` bytes will * land at the beginning of the contents of the new array. When * we're done copying, we overwrite the full first word with * the actual length of the slice. */ let lengthmod := and(_length, 31) /** * @dev The multiplication in the next line is necessary * because when slicing multiples of 32 bytes (lengthmod == 0) * the following copy loop was copying the origin's length * and then ending prematurely not copying everything it should. */ let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) // Update free-memory pointer allocating the array padded to 32 bytes like the compiler does now. mstore(0x40, and(add(mc, 31), not(31))) } // If we want a zero-length slice let's just return a zero-length array. default { tempBytes := mload(0x40) // Zero out the 32 bytes slice we are about to return we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // If lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { /** * @dev cb is a circuit breaker in the for loop since there's * no said feature for inline assembly loops * cb = 1 - don't breaker * cb = 0 - break */ let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) } // The next line is the loop condition: while(uint256(mc < end) + cb == 2). eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // If any of these checks fails then arrays are not equal. if iszero(eq(mload(mc), mload(cc))) { // Unsuccess: success := 0 cb := 0 } } } default { // Unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // We know _preBytes_offset is 0. let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // If lengths don't match the arrays are not equal. switch eq(slength, mlength) case 1 { /** * @dev Slength can contain both the length and contents of the array * if length < 32 bytes so let's prepare for that * v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage */ if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // Blank the last byte which is the length. fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // Unsuccess: success := 0 } } default { /** * @dev cb is a circuit breaker in the for loop since there's * no said feature for inline assembly loops * cb = 1 - don't breaker * cb = 0 - break */ let cb := 1 // Get the keccak hash to get the contents of the array. mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // The next line is the loop condition: while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // Unsuccess: success := 0 cb := 0 } } } } } default { // Unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// 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: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title ISwapper * * @author Fujidao Labs * * @notice Defines the interface for routers to perform token swaps with DEX protocols. * * @dev Implementation inheriting this interface should be permisionless. */ interface ISwapper { /** * @notice Swap tokens at exchange. * * @param assetIn address of the ERC-20 token to swap from * @param assetOut address of the ERC-20 token to swap to * @param amountIn that will be pulled from msg.sender * @param amountOut of `assetOut` expected after the swap * @param receiver of the `amountOut` tokens * @param sweeper who receives the leftovers `assetIn` tokens after swap * @param minSweepOut amount of `assetIn` leftover expected after swap * * @dev Slippage is controlled through `minSweepOut`. If `minSweepOut` is 0, * the slippage check gets skipped. */ function swap( address assetIn, address assetOut, uint256 amountIn, uint256 amountOut, address receiver, address sweeper, uint256 minSweepOut ) external; /** * @notice Estimate the amount of `assetIn` required for `swap()`. * * @param assetIn address of the ERC-20 token to swap from * @param assetOut address of the ERC-20 token to swap to * @param amountOut expected amount of `assetOut` after the swap */ function getAmountIn( address assetIn, address assetOut, uint256 amountOut ) external view returns (uint256 amountIn); /** * @notice Estimate the amount of `assetOut` received after swap * * @param assetIn address of the ERC-20 token to swap from * @param assetOut address of the ERC-20 token to swap to * @param amountIn of `assetIn` to perform swap */ function getAmountOut( address assetIn, address assetOut, uint256 amountIn ) external view returns (uint256 amountOut); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title SystemAccessControl * * @author Fujidao Labs * * @notice Abstract contract that should be inherited by contract implementations that * call the {Chief} contract for access control checks. */ import {IChief} from "../interfaces/IChief.sol"; import {CoreRoles} from "./CoreRoles.sol"; contract SystemAccessControl is CoreRoles { /// @dev Custom Errors error SystemAccessControl__hasRole_missingRole(address caller, bytes32 role); error SystemAccessControl__onlyTimelock_callerIsNotTimelock(); error SystemAccessControl__onlyHouseKeeper_notHouseKeeper(); IChief public immutable chief; /** * @dev Modifier that checks `caller` has `role`. */ modifier hasRole(address caller, bytes32 role) { if (!chief.hasRole(role, caller)) { revert SystemAccessControl__hasRole_missingRole(caller, role); } _; } /** * @dev Modifier that checks `msg.sender` has HOUSE_KEEPER_ROLE. */ modifier onlyHouseKeeper() { if (!chief.hasRole(HOUSE_KEEPER_ROLE, msg.sender)) { revert SystemAccessControl__onlyHouseKeeper_notHouseKeeper(); } _; } /** * @dev Modifier that checks `msg.sender` is the defined `timelock` in {Chief} * contract. */ modifier onlyTimelock() { if (msg.sender != chief.timelock()) { revert SystemAccessControl__onlyTimelock_callerIsNotTimelock(); } _; } /** * @notice Abstract constructor of a new {SystemAccessControl}. * * @param chief_ address * * @dev Requirements: * - Must pass non-zero {Chief} address, that could be checked at child contract. */ constructor(address chief_) { chief = IChief(chief_); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol"; import "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; import {IVault} from "./IVault.sol"; /** * @title ILendingProvider * * @author Fujidao Labs * * @notice Defines the interface for core engine to perform operations at lending providers. * * @dev Functions are intended to be called in the context of a Vault via delegateCall, * except indicated. */ interface ILendingProvider { function providerName() external view returns (string memory); /** * @notice Returns the operator address that requires ERC20-approval for vault operations. * * @param keyAsset address to inquiry operator * @param asset address of the calling vault * @param debtAsset address of the calling vault. Note: if {YieldVault} this will be address(0). * * @dev Provider implementations may or not require all 3 inputs. */ function approvedOperator( address keyAsset, address asset, address debtAsset ) external view returns (address operator); /** * @notice Performs deposit operation at lending provider on behalf vault. * * @param amount amount to deposit * @param vault IVault calling this function * * @dev Requirements: * - This function should be delegate called in the context of a `vault`. */ function deposit(uint256 amount, IVault vault) external returns (bool success); /** * @notice Performs borrow operation at lending provider on behalf vault. * * @param amount amount to borrow * @param vault IVault calling this function * * @dev Requirements: * - This function should be delegate called in the context of a `vault`. */ function borrow(uint256 amount, IVault vault) external returns (bool success); /** * @notice Performs withdraw operation at lending provider on behalf vault. * @param amount amount to withdraw * @param vault IVault calling this function. * * @dev Requirements: * - This function should be delegate called in the context of a `vault`. */ function withdraw(uint256 amount, IVault vault) external returns (bool success); /** * * @notice Performs payback operation at lending provider on behalf vault. * * @param amount amount to payback * @param vault IVault calling this function. * * @dev Requirements: * - This function should be delegate called in the context of a `vault`. * - Check there is erc20-approval to `approvedOperator` by the `vault` prior to call. */ function payback(uint256 amount, IVault vault) external returns (bool success); /** * @notice Returns DEPOSIT balance of 'user' at lending provider. * * @param user address whom balance is needed * @param vault IVault required by some specific providers with multi-markets, otherwise pass address(0). * * @dev Requirements: * - Must not require Vault context. */ function getDepositBalance(address user, IVault vault) external view returns (uint256 balance); /** * @notice Returns BORROW balance of 'user' at lending provider. * * @param user address whom balance is needed * @param vault IVault required by some specific providers with multi-markets, otherwise pass address(0). * * @dev Requirements: * - Must not require Vault context. */ function getBorrowBalance(address user, IVault vault) external view returns (uint256 balance); /** * @notice Returns the latest SUPPLY annual percent rate (APR) at lending provider. * * @param vault IVault required by some specific providers with multi-markets, otherwise pass address(0) * * @dev Requirements: * - Must return the rate in ray units (1e27) * Example 8.5% APR = 0.085 x 1e27 = 85000000000000000000000000 * - Must not require Vault context. */ function getDepositRateFor(IVault vault) external view returns (uint256 rate); /** * @notice Returns the latest BORROW annual percent rate (APR) at lending provider. * * @param vault IVault required by some specific providers with multi-markets, otherwise pass address(0) * * @dev Requirements: * - Must return the rate in ray units (1e27) * Example 8.5% APR = 0.085 x 1e27 = 85000000000000000000000000 * - Must not require Vault context. */ function getBorrowRateFor(IVault vault) external view returns (uint256 rate); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title IFujiOracle * * @author Fujidao Labs * * @notice Defines the interface of the {FujiOracle}. */ interface IFujiOracle { /** * @dev Emit when a change in price feed address is done for an `asset`. * * @param asset address * @param newPriceFeedAddress that returns USD price from Chainlink */ event AssetPriceFeedChanged(address asset, address newPriceFeedAddress); /** * @notice Returns the exchange rate between two assets, with price oracle given in * specified `decimals`. * * @param currencyAsset to be used, zero-address for USD * @param commodityAsset to be used, zero-address for USD * @param decimals of the desired price output * * @dev Price format is defined as: (amount of currencyAsset per unit of commodityAsset Exchange Rate). * Requirements: * - Must check that both `currencyAsset` and `commodityAsset` are set in * usdPriceFeeds, otherwise return zero. */ function getPriceOf( address currencyAsset, address commodityAsset, uint8 decimals ) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// 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; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.15; /** * @title CoreRoles * * @author Fujidao Labs * * @notice System definition of roles used across FujiV2 contracts. */ contract CoreRoles { bytes32 public constant HOUSE_KEEPER_ROLE = keccak256("HOUSE_KEEPER_ROLE"); bytes32 public constant REBALANCER_ROLE = keccak256("REBALANCER_ROLE"); bytes32 public constant HARVESTER_ROLE = keccak256("HARVESTER_ROLE"); bytes32 public constant LIQUIDATOR_ROLE = keccak256("LIQUIDATOR_ROLE"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); bytes32 public constant UNPAUSER_ROLE = keccak256("UNPAUSER_ROLE"); }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "nxtp/=lib/nxtp/packages/deployments/contracts/contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IWETH9","name":"weth","type":"address"},{"internalType":"contract IConnext","name":"connext_","type":"address"},{"internalType":"contract IChief","name":"chief","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BaseRouter__allowCaller_noAllowChange","type":"error"},{"inputs":[],"name":"BaseRouter__allowCaller_zeroAddress","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_flashloanInvalidRequestor","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_insufficientETH","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_insufficientFlashloanBalance","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_noBalanceChange","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_notAllowedFlasher","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_notAllowedSwapper","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_notBeneficiary","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_paramsMismatch","type":"error"},{"inputs":[],"name":"BaseRouter__bundleInternal_swapNotFirstAction","type":"error"},{"inputs":[],"name":"BaseRouter__checkVaultInput_notActiveVault","type":"error"},{"inputs":[],"name":"BaseRouter__fallback_notAllowed","type":"error"},{"inputs":[],"name":"BaseRouter__handlePermit_notPermitAction","type":"error"},{"inputs":[],"name":"BaseRouter__receive_senderNotWETH","type":"error"},{"inputs":[],"name":"BaseRouter__safeTransferETH_transferFailed","type":"error"},{"inputs":[],"name":"ConnextRouter__setRouter_invalidInput","type":"error"},{"inputs":[],"name":"ConnextRouter__xReceive_notAllowedCaller","type":"error"},{"inputs":[],"name":"ConnextRouter__xReceive_notReceivedAssetBalance","type":"error"},{"inputs":[],"name":"ConnextRouter__xReceiver_noValueTransferUseXbundle","type":"error"},{"inputs":[],"name":"ConnnextRouter__xBundleConnext_notSelfCalled","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"SystemAccessControl__hasRole_missingRole","type":"error"},{"inputs":[],"name":"SystemAccessControl__onlyHouseKeeper_notHouseKeeper","type":"error"},{"inputs":[],"name":"SystemAccessControl__onlyTimelock_callerIsNotTimelock","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowCaller","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"router","type":"address"},{"indexed":true,"internalType":"uint256","name":"domain","type":"uint256"}],"name":"NewRouterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"destDomain","type":"uint256"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"}],"name":"XCalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"originDomain","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"}],"name":"XReceived","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"HARVESTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HOUSE_KEEPER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REBALANCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"contract IWETH9","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"bumpTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"chief","outputs":[{"internalType":"contract IChief","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"connext","outputs":[{"internalType":"contract IConnext","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"handler","outputs":[{"internalType":"contract ConnextHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAllowedCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"routerByDomain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"domain","type":"uint256"},{"internalType":"address","name":"router","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"sweepETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IRouter.Action[]","name":"actions","type":"uint8[]"},{"internalType":"bytes[]","name":"args","type":"bytes[]"}],"name":"xBundle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"enum IRouter.Action[]","name":"actions","type":"uint8[]"},{"internalType":"bytes[]","name":"args","type":"bytes[]"},{"internalType":"uint256","name":"beforeSlipped","type":"uint256"}],"name":"xBundleConnext","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"uint32","name":"originDomain","type":"uint32"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"xReceive","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101006040523480156200001257600080fd5b5060405162005de838038062005de88339810160408190526200003591620001a0565b6001600160a01b0380821660805280841660a052821660c05260405130906200005e9062000179565b6001600160a01b039091168152602001604051809103906000f0801580156200008b573d6000803e3d6000fd5b506001600160a01b031660e052620000a5336001620000ae565b505050620001f4565b6001600160a01b038216620000d657604051632cdf6c4b60e11b815260040160405180910390fd5b6001600160a01b03821660009081526020819052604090205481151560ff90911615150362000118576040516332fe3f1960e21b815260040160405180910390fd5b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f6bf208b256dacdc89831fd5124ada2aa0f56252c178dd5aff85ee68daf0a7f1c910160405180910390a15050565b61182880620045c083390190565b6001600160a01b03811681146200019d57600080fd5b50565b600080600060608486031215620001b657600080fd5b8351620001c38162000187565b6020850151909350620001d68162000187565b6040850151909250620001e98162000187565b809150509250925092565b60805160a05160c05160e051614306620002ba600039600081816103c801528181610c2b0152610c670152600081816103fc0152818161073901528181612442015281816124c10152818161260f01526126380152600081816101330152818161029f015281816118550152818161187e0152818161194901526119870152600081816104f90152818161051d01528181610686015281816107dd015281816109580152818161167801528181611d060152818161279b01526128a801526143066000f3fe6080604052600436106101235760003560e01c80637270bdb0116100a0578063e63ab1e911610064578063e63ab1e91461041e578063f4200a1414610452578063fb1bb9de14610486578063fd614f41146104ba578063ffd864d3146104e757610173565b80637270bdb014610343578063a3fb20f414610363578063a680125814610376578063c80916d4146103b6578063de4b0548146103ea57610173565b80633fb9a94e116100e75780633fb9a94e14610246578063490b48f8146102595780634aa4a4fc1461028d5780635955003c146102d957806363a560ec1461030f57610173565b8063087de6f71461018c5780631163b2b0146101ac57806316d8887a146101cc5780632424401f14610213578063258836fe1461022657610173565b3661017357336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610171576040516372643aad60e01b815260040160405180910390fd5b005b60405163c6a579c760e01b815260040160405180910390fd5b34801561019857600080fd5b506101716101a7366004613582565b61051b565b3480156101b857600080fd5b506101716101c73660046135b2565b61064b565b3480156101d857600080fd5b506102007f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1681565b6040519081526020015b60405180910390f35b6101716102213660046135d6565b610723565b34801561023257600080fd5b506101716102413660046135ef565b6107a2565b610171610254366004613668565b6108e6565b34801561026557600080fd5b506102007fccc64574297998b6c3edf6078cc5e01268465ff116954e3af02ff3a70a730f4681565b34801561029957600080fd5b506102c17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161020a565b3480156102e557600080fd5b506102c16102f43660046135d6565b6003602052600090815260409020546001600160a01b031681565b34801561031b57600080fd5b506102007f3fc733b4d20d27a28452ddf0e9351aced28242fe03389a653cdb783955316b9b81565b34801561034f57600080fd5b5061017161035e3660046136e9565b610956565b610171610371366004613717565b610a13565b34801561038257600080fd5b506103a66103913660046135b2565b60006020819052908152604090205460ff1681565b604051901515815260200161020a565b3480156103c257600080fd5b506102c17f000000000000000000000000000000000000000000000000000000000000000081565b3480156103f657600080fd5b506102c17f000000000000000000000000000000000000000000000000000000000000000081565b34801561042a57600080fd5b506102007f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b34801561045e57600080fd5b506102007fe9e995cadb4a71c3f5032f9fbf95a1e1369b940625a86946b14b2d845bf747ab81565b34801561049257600080fd5b506102007f427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a81565b3480156104c657600080fd5b506104da6104d5366004613845565b610a63565b60405161020a919061392c565b3480156104f357600080fd5b506102c17f000000000000000000000000000000000000000000000000000000000000000081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d33219b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059d919061393f565b6001600160a01b0316336001600160a01b0316146105ce5760405163b909292960e01b815260040160405180910390fd5b6001600160a01b0381166105f55760405163388732eb60e01b815260040160405180910390fd5b60008281526003602052604080822080546001600160a01b0319166001600160a01b038516908117909155905184927f038088a234c0d1d17a5f4c755e87c5283845155cf3344f6c977eedca1275ef1591a35050565b604051632474521560e21b81527fe9e995cadb4a71c3f5032f9fbf95a1e1369b940625a86946b14b2d845bf747ab60048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906391d1485490604401602060405180830381865afa1580156106d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f9919061395c565b61071657604051639c73fc7f60e01b815260040160405180910390fd5b6107208147610db2565b50565b604051632424401f60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632424401f9034906024016000604051808303818588803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b505050505050565b604051632474521560e21b81527fe9e995cadb4a71c3f5032f9fbf95a1e1369b940625a86946b14b2d845bf747ab60048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906391d1485490604401602060405180830381865afa15801561082c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610850919061395c565b61086d57604051639c73fc7f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526108e290839083906001600160a01b038316906370a0823190602401602060405180830381865afa1580156108b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dd9190613979565b610e45565b5050565b33301461090657604051633228cc7160e21b815260040160405180910390fd5b61094f85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061094992508691508790506139b5565b83610ea8565b5050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d33219b46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d8919061393f565b6001600160a01b0316336001600160a01b031614610a095760405163b909292960e01b815260040160405180910390fd5b6108e28282611a16565b610a5d848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a5692508591508690506139b5565b6000610ea8565b50505050565b606060008083806020019051810190610a7c9190613b60565b90925090506000808915610bc9576040516370a0823160e01b81523060048201526001600160a01b038a16906370a0823190602401602060405180830381865afa158015610ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af29190613979565b915089821015610b155760405163018884f160e51b815260040160405180910390fd5b60405180604001604052808a6001600160a01b031681526020018b84610b3b9190613bd9565b90528051600180546001600160a01b039092166001600160a01b031990921691909117905560200151600255610ba68a85600081518110610b7e57610b7e613bf0565b602002602001015185600081518110610b9957610b99613bf0565b6020026020010151611adf565b84600081518110610bb957610bb9613bf0565b6020026020010181935082905250505b604051631fdcd4a760e11b81523090633fb9a94e90610bf090879087908690600401613cca565b600060405180830381600087803b158015610c0a57600080fd5b505af1925050508015610c1b575060015b610d4d578115610cdb57610c50897f000000000000000000000000000000000000000000000000000000000000000084610e45565b60405163e667df2f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e667df2f90610ca8908e908e908e908e908e908c908c90600401613d00565b600060405180830381600087803b158015610cc257600080fd5b505af1158015610cd6573d6000803e3d6000fd5b505050505b6001600080820160006101000a8154906001600160a01b030219169055600182016000905550508663ffffffff168b7f62277c9bd483b2bd832cf3849e52ec0a2b1e4297f133ccb28e963239a8007f5a60008c8e8b604051610d409493929190613d65565b60405180910390a3610d94565b8663ffffffff168b7f62277c9bd483b2bd832cf3849e52ec0a2b1e4297f133ccb28e963239a8007f5a60018c8e8b604051610d8b9493929190613d65565b60405180910390a35b50506040805160208101909152600081529998505050505050505050565b604080516000808252602082019092526001600160a01b038416908390604051610ddc9190613d9e565b60006040518083038185875af1925050503d8060008114610e19576040519150601f19603f3d011682016040523d82523d6000602084013e610e1e565b606091505b5050905080610e40576040516322462d1f60e01b815260040160405180910390fd5b505050565b6040516001600160a01b038316602482015260448101829052610e4090849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611c0d565b825182518114610ecb576040516305b9af8f60e51b815260040160405180910390fd5b60408051600a808252610160820190925260009182918291816020015b6040805180820190915260008082526020820152815260200190600190039081610ee85750506001549091506001600160a01b031615610f6157604080518082019091526001546001600160a01b03168152600254602082015281518290600090610f5557610f55613bf0565b60200260200101819052505b6000610f6d3447613bd9565b905060005b85811015611a01576000898281518110610f8e57610f8e613bf0565b602002602001015190506000600b811115610fab57610fab613c06565b81600b811115610fbd57610fbd613c06565b03611119576000806000808c8681518110610fda57610fda613bf0565b6020026020010151806020019051810190610ff59190613dba565b935093509350935061100684611ce7565b6000846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106a919061393f565b90506110768b84611d8e565b9a50611082818a611de0565b985061108f818386611eb9565b61109a818686611eeb565b604051636e553f6560e01b8152600481018590526001600160a01b038481166024830152861690636e553f65906044015b6020604051808303816000875af11580156110ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110e9190613979565b5050505050506119f8565b600181600b81111561112d5761112d613c06565b03611277576000806000808c868151811061114a5761114a613bf0565b60200260200101518060200190518101906111659190613dba565b935093509350935061117684611ce7565b6111808a82611d8e565b99506111ed846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e7919061393f565b89611de0565b604051632d182be560e21b8152600481018590526001600160a01b03848116602483015283811660448301529199509085169063b460af94906064015b6020604051808303816000875af1158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d9190613979565b50505050506119f8565b600281600b81111561128b5761128b613c06565b03611362576000806000808c86815181106112a8576112a8613bf0565b60200260200101518060200190518101906112c39190613dba565b93509350935093506112d484611ce7565b6112de8a82611d8e565b9950611321846001600160a01b031663a919802d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c3573d6000803e3d6000fd5b604051633545906160e21b8152600481018590526001600160a01b03848116602483015283811660448301529199509085169063d51641849060640161122a565b600381600b81111561137657611376613c06565b03611488576000806000808c868151811061139357611393613bf0565b60200260200101518060200190518101906113ae9190613dba565b93509350935093506113bf84611ce7565b6000846001600160a01b031663a919802d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611423919061393f565b905061142f8b84611d8e565b9a5061143b818a611de0565b9850611448818386611eb9565b611453818686611eeb565b60405163d084b9af60e01b8152600481018590526001600160a01b03848116602483015286169063d084b9af906044016110cb565b600681600b81111561149c5761149c613c06565b036114ee57846114b4576114b18a8a8a611ef6565b94505b60006114da828b85815181106114cc576114cc613bf0565b602002602001015188612221565b90506114e68782611d8e565b9650506119f8565b600781600b81111561150257611502613c06565b0361151757846114b4576114b18a8a8a611ef6565b600881600b81111561152b5761152b613c06565b0361155a5761155389838151811061154557611545613bf0565b6020026020010151876123f8565b95506119f8565b600981600b81111561156e5761156e613c06565b036115965761155389838151811061158857611588613bf0565b6020026020010151876125a2565b600581600b8111156115aa576115aa613c06565b036115fe57816000036115d05760405163b42fccab60e01b815260040160405180910390fd5b6115f48983815181106115e5576115e5613bf0565b60200260200101518786612765565b90965093506119f8565b600481600b81111561161257611612613c06565b036117e65760008060008060008d878151811061163157611631613bf0565b602002602001015180602001905181019061164c9190613e0f565b6040516306a33c7960e51b81526001600160a01b038681166004830152959a50939850919650945092507f00000000000000000000000000000000000000000000000000000000000000009091169063d4678f2090602401602060405180830381865afa1580156116c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e5919061395c565b61170257604051631ddd578f60e11b815260040160405180910390fd5b6001600160a01b038216301461172b5760405163ef34858960e01b815260040160405180910390fd5b611735848a611de0565b985060008061175283600480865161174d9190613bd9565b6129df565b8060200190518101906117659190613b60565b915091506117738282612aec565b604051631f8aa39560e21b8152909d506001600160a01b03881690637e2a8e54906117a8908990899089908990600401613e90565b600060405180830381600087803b1580156117c257600080fd5b505af11580156117d6573d6000803e3d6000fd5b50505050505050505050506119f8565b600a81600b8111156117fa576117fa613c06565b036118eb57600089838151811061181357611813613bf0565b602002602001015180602001905181019061182e9190613979565b9050348114611850576040516379eecdfb60e11b815260040160405180910390fd5b61187a7f000000000000000000000000000000000000000000000000000000000000000086611de0565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156118d757600080fd5b505af115801561110e573d6000803e3d6000fd5b600b81600b8111156118ff576118ff613c06565b036119f8576000808a848151811061191957611919613bf0565b60200260200101518060200190518101906119349190613ec3565b915091506119428882611d8e565b975061196e7f000000000000000000000000000000000000000000000000000000000000000087611de0565b604051632e1a7d4d60e01b8152600481018490529096507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156119d357600080fd5b505af11580156119e7573d6000803e3d6000fd5b505050506119f58183610db2565b50505b50600101610f72565b50611a0c82826130ef565b5050505050505050565b6001600160a01b038216611a3d57604051632cdf6c4b60e11b815260040160405180910390fd5b6001600160a01b03821660009081526020819052604090205481151560ff909116151503611a7e576040516332fe3f1960e21b815260040160405180910390fd5b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f6bf208b256dacdc89831fd5124ada2aa0f56252c178dd5aff85ee68daf0a7f1c910160405180910390a15050565b8060008084600b811115611af557611af5613c06565b1480611b125750600384600b811115611b1057611b10613c06565b145b15611b8d5760008060008086806020019051810190611b319190613dba565b9350935093509350888314611b8457604080516001600160a01b0380871660208301529181018b905281841660608201529082166080820152929450849260a00160405160208183030381529060405295505b50505050611c05565b600b84600b811115611ba157611ba1613c06565b03611c055760008084806020019051810190611bbd9190613ec3565b91509150868214611c02578192508681604051602001611bf09291909182526001600160a01b0316602082015260400190565b60405160208183030381529060405293505b50505b935093915050565b6000611c62826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661322c9092919063ffffffff16565b9050805160001480611c83575080806020019051810190611c83919061395c565b610e405760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b604051630c5aed5760e01b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630c5aed5790602401602060405180830381865afa158015611d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d71919061395c565b6107205760405163106f25d560e31b815260040160405180910390fd5b60006001600160a01b038316611da5575080611dda565b816001600160a01b0316836001600160a01b031614611dd757604051630727952560e41b815260040160405180910390fd5b50805b92915050565b6060600080611def8585613243565b9150915081611eb05760008115611e1057611e0b826001613ee8565b611e12565b815b6040805180820182526001600160a01b03891680825291516370a0823160e01b8152306004820152929350916020830191906370a0823190602401602060405180830381865afa158015611e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8e9190613979565b815250858281518110611ea357611ea3613bf0565b6020026020010181905250505b50919392505050565b6001600160a01b0382163014801590611eda57506001600160a01b03821633145b15610e4057610e40838330846132a7565b610e408383836132df565b825160009081816001600160401b03811115611f1457611f14613782565b604051908082528060200260200182016040528015611f4757816020015b6060815260200190600190039081611f325790505b50905060005b828110156121ec57858181518110611f6757611f67613bf0565b6020026020010151828281518110611f8157611f81613bf0565b6020026020010181905250806000148015611f9b57508415155b801561200557506000878281518110611fb657611fb6613bf0565b6020026020010151600b811115611fcf57611fcf613c06565b148061200557506003878281518110611fea57611fea613bf0565b6020026020010151600b81111561200357612003613c06565b145b156120ab5760008060008085858151811061202257612022613bf0565b602002602001015180602001905181019061203d9190613dba565b93509350935093508289146120a657604080516001600160a01b0380871660208301529181018b90528184166060820152908216608082015260a00160405160208183030381529060405286868151811061209a5761209a613bf0565b60200260200101819052505b505050505b60068782815181106120bf576120bf613bf0565b6020026020010151600b8111156120d8576120d8613c06565b148061210e575060078782815181106120f3576120f3613bf0565b6020026020010151600b81111561210c5761210c613c06565b145b156121da5760008060008085858151811061212b5761212b613bf0565b60200260200101518060200190518101906121469190613f00565b5050604080516001600160a01b038089166020830152808816828401528616606082015260808101859052600060a0820181905260c0820181905260e08201819052610100808301919091528251808303909101815261012090910190915295995093975091955093506121b8915050565b8686815181106121ca576121ca613bf0565b6020026020010181905250505050505b806121e481613f8c565b915050611f4d565b508581604051602001612200929190613fa5565b60405160208183030381529060405280519060200120925050509392505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052838060200190518101906122759190613f00565b60e089015260c088015260ff1660a0870152608086015260608501526001600160a01b0390811660408501529081166020840152168082526122b690611ce7565b600685600b8111156122ca576122ca613c06565b036123605780600001516001600160a01b0316630fad31318260200151836040015184606001518560800151888760a001518860c001518960e001516040518963ffffffff1660e01b8152600401612329989796959493929190613fd3565b600060405180830381600087803b15801561234357600080fd5b505af1158015612357573d6000803e3d6000fd5b505050506123ec565b600785600b81111561237457612374613c06565b036123d35780600001516001600160a01b03166396ebbc458260200151836040015184606001518560800151888760a001518860c001518960e001516040518963ffffffff1660e01b8152600401612329989796959493929190613fd3565b604051632f67478960e21b815260040160405180910390fd5b60200151949350505050565b600080600080600080600088806020019051810190612417919061401a565b955095509550955095509550600061242f8984611d8e565b905061243c858386611eb9565b612467857f000000000000000000000000000000000000000000000000000000000000000086611eeb565b6040516345560b5d60e11b815263ffffffff881660048201526001600160a01b038481166024830152868116604483015282811660648301526084820186905260a4820188905260e060c4830152600060e48301819052917f000000000000000000000000000000000000000000000000000000000000000090911690638aac16ba90610104016020604051808303816000875af115801561250d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125319190613979565b604080518a81526001600160a01b038981166020830152918101889052608060608201819052600090820152919250851690339083907fb7c6eb876c99dadc81a4df296037aa08e5c6be07a3765524cf8812aec701f7e49060a00160405180910390a4509998505050505050505050565b6000806000806000806000888060200190518101906125c19190614083565b955095509550955095509550600080828060200190518101906125e491906140f5565b50915091506125fc8a6125f78484612aec565b611d8e565b9850612609868587611eb9565b612634867f000000000000000000000000000000000000000000000000000000000000000087611eeb565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638aac16ba8a600360008d815260200190815260200160002060009054906101000a90046001600160a01b03168a8e8b8e8b6040518863ffffffff1660e01b81526004016126b49796959493929190614161565b6020604051808303816000875af11580156126d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f79190613979565b60008a815260036020526040908190205490519192506001600160a01b031690339083907fb7c6eb876c99dadc81a4df296037aa08e5c6be07a3765524cf8812aec701f7e49061274e908e908d908d908c906141bc565b60405180910390a450505050505050505092915050565b600060606000806000806000806000808c80602001905181019061278991906141e9565b975097509750975097509750975097507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663877945f0896040518263ffffffff1660e01b81526004016127f491906001600160a01b0391909116815260200190565b602060405180830381865afa158015612811573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612835919061395c565b6128525760405163418f824160e01b815260040160405180910390fd5b61285c878c611de0565b9a50612868868c611de0565b9a50612875878987611eeb565b6001600160a01b038316301480159061291557506040516306a33c7960e51b81526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063d4678f2090602401602060405180830381865afa1580156128ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612913919061395c565b155b15612927576129248c84611d8e565b9b505b6001600160a01b0382163014612944576129418c83611d8e565b9b505b60405163e2c4f23b60e01b81526001600160a01b03888116600483015287811660248301526044820187905260648201869052848116608483015283811660a483015260c4820183905289169063e2c4f23b9060e401600060405180830381600087803b1580156129b457600080fd5b505af11580156129c8573d6000803e3d6000fd5b509d9f9c9e509b9c50505050505050505050505050565b6060816129ed81601f613ee8565b1015612a2c5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401611cde565b612a368284613ee8565b84511015612a7a5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401611cde565b606082158015612a995760405191506000825260208201604052612ae3565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612ad2578051835260209283019201612aba565b5050858452601f01601f1916604052505b50949350505050565b60008083600081518110612b0257612b02613bf0565b6020026020010151600b811115612b1b57612b1b613c06565b1480612b525750600383600081518110612b3757612b37613bf0565b6020026020010151600b811115612b5057612b50613c06565b145b15612b9357600082600081518110612b6c57612b6c613bf0565b6020026020010151806020019051810190612b879190613dba565b509350611dda92505050565b600183600081518110612ba857612ba8613bf0565b6020026020010151600b811115612bc157612bc1613c06565b1480612bf85750600283600081518110612bdd57612bdd613bf0565b6020026020010151600b811115612bf657612bf6613c06565b145b15612c3957600082600081518110612c1257612c12613bf0565b6020026020010151806020019051810190612c2d9190613dba565b9450611dda9350505050565b600b83600081518110612c4e57612c4e613bf0565b6020026020010151600b811115612c6757612c67613c06565b03612ca657600082600081518110612c8157612c81613bf0565b6020026020010151806020019051810190612c9c9190613ec3565b9250611dda915050565b600783600081518110612cbb57612cbb613bf0565b6020026020010151600b811115612cd457612cd4613c06565b1480612d0b5750600683600081518110612cf057612cf0613bf0565b6020026020010151600b811115612d0957612d09613c06565b145b15612d5157600082600081518110612d2557612d25613bf0565b6020026020010151806020019051810190612d409190613f00565b50949750611dda9650505050505050565b600483600081518110612d6657612d66613bf0565b6020026020010151600b811115612d7f57612d7f613c06565b03612dfb57600082600081518110612d9957612d99613bf0565b6020026020010151806020019051810190612db49190613e0f565b945050505050600080612dd083600480865161174d9190613bd9565b806020019051810190612de39190613b60565b91509150612df18282612aec565b9350505050611dda565b600883600081518110612e1057612e10613bf0565b6020026020010151600b811115612e2957612e29613c06565b03612e6c57600082600081518110612e4357612e43613bf0565b6020026020010151806020019051810190612e5e919061401a565b509550611dda945050505050565b600983600081518110612e8157612e81613bf0565b6020026020010151600b811115612e9a57612e9a613c06565b03612efb57600082600081518110612eb457612eb4613bf0565b6020026020010151806020019051810190612ecf919061427c565b94505050505060008082806020019051810190612eec91906140f5565b5091509150612df18282612aec565b600a83600081518110612f1057612f10613bf0565b6020026020010151600b811115612f2957612f29613c06565b036130a35782516000612f3d600183613bd9565b6001600160401b03811115612f5457612f54613782565b604051908082528060200260200182016040528015612f7d578160200160208202803683370190505b5090506000612f8d600184613bd9565b6001600160401b03811115612fa457612fa4613782565b604051908082528060200260200182016040528015612fd757816020015b6060815260200190600190039081612fc25790505b50905060015b8381101561309857868181518110612ff757612ff7613bf0565b60200260200101518360018361300d9190613bd9565b8151811061301d5761301d613bf0565b6020026020010190600b81111561303657613036613c06565b9081600b81111561304957613049613c06565b8152505085818151811061305f5761305f613bf0565b6020026020010151826001836130759190613bd9565b8151811061308557613085613bf0565b6020908102919091010152600101612fdd565b50612df18282612aec565b6005836000815181106130b8576130b8613bf0565b6020026020010151600b8111156130d1576130d1613c06565b03611dda5760405163b42fccab60e01b815260040160405180910390fd5b815160005b8181101561320b5760006001600160a01b031684828151811061311957613119613bf0565b6020026020010151600001516001600160a01b03161461320357600084828151811061314757613147613bf0565b6020026020010151602001519050600085838151811061316957613169613bf0565b6020908102919091010151516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156131ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131de9190613979565b905081811461320057604051632c1b2f5f60e21b815260040160405180910390fd5b50505b6001016130f4565b50478214610e4057604051632c1b2f5f60e21b815260040160405180910390fd5b606061323b84846000856133f4565b949350505050565b80516000908190815b8181101561329e5784818151811061326657613266613bf0565b6020026020010151600001516001600160a01b0316866001600160a01b031603613296576001935080925061329e565b60010161324c565b50509250929050565b6040516001600160a01b0380851660248301528316604482015260648101829052610a5d9085906323b872dd60e01b90608401610e71565b8015806133595750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613333573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133579190613979565b155b6133c45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401611cde565b6040516001600160a01b038316602482015260448101829052610e4090849063095ea7b360e01b90606401610e71565b6060824710156134555760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611cde565b600080866001600160a01b031685876040516134719190613d9e565b60006040518083038185875af1925050503d80600081146134ae576040519150601f19603f3d011682016040523d82523d6000602084013e6134b3565b606091505b50915091506134c4878383876134cf565b979650505050505050565b6060831561353e578251600003613537576001600160a01b0385163b6135375760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611cde565b508161323b565b61323b83838151156135535781518083602001fd5b8060405162461bcd60e51b8152600401611cde919061392c565b6001600160a01b038116811461072057600080fd5b6000806040838503121561359557600080fd5b8235915060208301356135a78161356d565b809150509250929050565b6000602082840312156135c457600080fd5b81356135cf8161356d565b9392505050565b6000602082840312156135e857600080fd5b5035919050565b6000806040838503121561360257600080fd5b823561360d8161356d565b915060208301356135a78161356d565b60008083601f84011261362f57600080fd5b5081356001600160401b0381111561364657600080fd5b6020830191508360208260051b850101111561366157600080fd5b9250929050565b60008060008060006060868803121561368057600080fd5b85356001600160401b038082111561369757600080fd5b6136a389838a0161361d565b909750955060208801359150808211156136bc57600080fd5b506136c98882890161361d565b96999598509660400135949350505050565b801515811461072057600080fd5b600080604083850312156136fc57600080fd5b82356137078161356d565b915060208301356135a7816136db565b6000806000806040858703121561372d57600080fd5b84356001600160401b038082111561374457600080fd5b6137508883890161361d565b9096509450602087013591508082111561376957600080fd5b506137768782880161361d565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156137c0576137c0613782565b604052919050565b60006001600160401b038211156137e1576137e1613782565b50601f01601f191660200190565b600082601f83011261380057600080fd5b813561381361380e826137c8565b613798565b81815284602083860101111561382857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561385e57600080fd5b863595506020870135945060408701356138778161356d565b935060608701356138878161356d565b9250608087013563ffffffff811681146138a057600080fd5b915060a08701356001600160401b038111156138bb57600080fd5b6138c789828a016137ef565b9150509295509295509295565b60005b838110156138ef5781810151838201526020016138d7565b83811115610a5d5750506000910152565b600081518084526139188160208601602086016138d4565b601f01601f19169290920160200192915050565b6020815260006135cf6020830184613900565b60006020828403121561395157600080fd5b81516135cf8161356d565b60006020828403121561396e57600080fd5b81516135cf816136db565b60006020828403121561398b57600080fd5b5051919050565b60006001600160401b038211156139ab576139ab613782565b5060051b60200190565b60006139c361380e84613992565b80848252602080830192508560051b8501368111156139e157600080fd5b855b81811015613a1c5780356001600160401b03811115613a025760008081fd5b613a0e36828a016137ef565b8652509382019382016139e3565b50919695505050505050565b600082601f830112613a3957600080fd5b81516020613a4961380e83613992565b82815260059290921b84018101918181019086841115613a6857600080fd5b8286015b84811015613a91578051600c8110613a845760008081fd5b8352918301918301613a6c565b509695505050505050565b600082601f830112613aad57600080fd5b8151613abb61380e826137c8565b818152846020838601011115613ad057600080fd5b61323b8260208301602087016138d4565b600082601f830112613af257600080fd5b81516020613b0261380e83613992565b82815260059290921b84018101918181019086841115613b2157600080fd5b8286015b84811015613a915780516001600160401b03811115613b445760008081fd5b613b528986838b0101613a9c565b845250918301918301613b25565b60008060408385031215613b7357600080fd5b82516001600160401b0380821115613b8a57600080fd5b613b9686838701613a28565b93506020850151915080821115613bac57600080fd5b50613bb985828601613ae1565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b600082821015613beb57613beb613bc3565b500390565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60008151808452602080850194508084016000805b84811015613c69578251600c8110613c5757634e487b7160e01b83526021600452602483fd5b88529683019691830191600101613c31565b50959695505050505050565b600081518084526020808501808196508360051b8101915082860160005b85811015613cbd578284038952613cab848351613900565b98850198935090840190600101613c93565b5091979650505050505050565b606081526000613cdd6060830186613c1c565b8281036020840152613cef8186613c75565b915050826040830152949350505050565b878152602081018790526001600160a01b0386811660408301528516606082015263ffffffff8416608082015260e060a08201819052600090613d4590830185613c1c565b82810360c0840152613d578185613c75565b9a9950505050505050505050565b841515815260018060a01b0384166020820152826040820152608060608201526000613d946080830184613900565b9695505050505050565b60008251613db08184602087016138d4565b9190910192915050565b60008060008060808587031215613dd057600080fd5b8451613ddb8161356d565b602086015160408701519195509350613df38161356d565b6060860151909250613e048161356d565b939692955090935050565b600080600080600060a08688031215613e2757600080fd5b8551613e328161356d565b6020870151909550613e438161356d565b604087015160608801519195509350613e5b8161356d565b60808701519092506001600160401b03811115613e7757600080fd5b613e8388828901613a9c565b9150509295509295909350565b6001600160a01b0385811682526020820185905283166040820152608060608201819052600090613d9490830184613900565b60008060408385031215613ed657600080fd5b8251915060208301516135a78161356d565b60008219821115613efb57613efb613bc3565b500190565b600080600080600080600080610100898b031215613f1d57600080fd5b8851613f288161356d565b60208a0151909850613f398161356d565b60408a0151909750613f4a8161356d565b80965050606089015194506080890151935060a089015160ff81168114613f7057600080fd5b60c08a015160e0909a0151989b979a5095989497939692505050565b600060018201613f9e57613f9e613bc3565b5060010190565b604081526000613fb86040830185613c1c565b8281036020840152613fca8185613c75565b95945050505050565b6001600160a01b03988916815296909716602087015260408601949094526060850192909252608084015260ff1660a083015260c082015260e08101919091526101000190565b60008060008060008060c0878903121561403357600080fd5b8651955060208701519450604087015161404c8161356d565b6060880151608089015191955093506140648161356d565b60a08801519092506140758161356d565b809150509295509295509295565b60008060008060008060c0878903121561409c57600080fd5b865195506020870151945060408701516140b58161356d565b6060880151608089015191955093506140cd8161356d565b60a08801519092506001600160401b038111156140e957600080fd5b6138c789828a01613a9c565b60008060006060848603121561410a57600080fd5b83516001600160401b038082111561412157600080fd5b61412d87838801613a28565b9450602086015191508082111561414357600080fd5b5061415086828701613ae1565b925050604084015190509250925092565b63ffffffff881681526001600160a01b0387811660208301528681166040830152851660608201526080810184905260a0810183905260e060c082018190526000906141af90830184613900565b9998505050505050505050565b84815260018060a01b0384166020820152826040820152608060608201526000613d946080830184613900565b600080600080600080600080610100898b03121561420657600080fd5b88516142118161356d565b60208a01519098506142228161356d565b60408a01519097506142338161356d565b80965050606089015194506080890151935060a08901516142538161356d565b60c08a01519093506142648161356d565b8092505060e089015190509295985092959890939650565b600080600080600060a0868803121561429457600080fd5b855194506020860151935060408601516142ad8161356d565b6060870151608088015191945092506001600160401b03811115613e7757600080fdfea2646970667358221220895d0472be94d1dce0b168504cb164620e17c452cff2b751dc482ac28487208264736f6c634300080f003360a060405234801561001057600080fd5b5060405161182838038061182883398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516117816100a760003960008181610107015281816101560152818161046a015281816104ff0152610bb901526117816000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806304395356146100675780631e8ce9b71461007c5780633347b553146100ac578063c0f3bc28146100cc578063e667df2f146100ef578063f36e558914610102575b600080fd5b61007a610075366004611147565b610141565b005b61008f61008a3660046111c5565b610712565b6040516001600160801b0390911681526020015b60405180910390f35b6100bf6100ba3660046111de565b610743565b6040516100a39190611317565b6100df6100da3660046111de565b610986565b60405190151581526020016100a3565b61007a6100fd3660046113f1565b610bae565b6101297f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100a3565b6040516314d0024b60e31b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a680125890602401602060405180830381865afa1580156101a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c991906114a5565b6101e657604051631bd4dfdf60e01b815260040160405180910390fd5b6000848152602081815260408083206001600160801b038716845282528083208151610120810183528154815260018201548185015260028201546001600160a01b039081168285015260038301549081166060830152600160a01b900463ffffffff1660808201526004820180548451818702810187019095528085529194929360a08601939092908301828280156102cf57602002820191906000526020600020906000905b82829054906101000a900460ff16600b8111156102ad576102ad61120a565b81526020600192830181810494850194909303909202910180841161028e5790505b5050505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b828210156103a957838290600052602060002001805461031c906114ce565b80601f0160208091040260200160405190810160405280929190818152602001828054610348906114ce565b80156103955780601f1061036a57610100808354040283529160200191610395565b820191906000526020600020905b81548152906001019060200180831161037857829003601f168201915b5050505050815260200190600101906102fd565b50505090825250600691909101546001600160801b0381166020830152600160801b900460ff161515604090910152805190915015806103f15750608081015163ffffffff16155b1561040f5760405163f359c15960e01b815260040160405180910390fd5b8061010001511561044957604051630a0ab2df60e01b8152600481018690526001600160801b038516602482015260440160405180910390fd5b6040818101516020830151915163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482019390935291169063095ea7b3906044016020604051808303816000875af11580156104c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e791906114a5565b506040516328fec83d60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a3fb20f4906105369086908690600401611537565b600060405180830381600087803b15801561055057600080fd5b505af1925050508015610561575060015b6105b65760001515857f0b927ce548896758f1bc8bb29b6650e47491626f1b708ab99a46412f5322445d8360a00151868560c00151878a6040516105a9959493929190611565565b60405180910390a361070b565b600161010082018190526000868152602081815260408083206001600160801b0389168452825291829020845181558185015193810193909355908301516002830180546001600160a01b039283166001600160a01b03199091161790556060840151600384018054608087015163ffffffff16600160a01b026001600160c01b0319909116929093169190911791909117905560a08301518051849392610665926004850192910190610dee565b5060c08201518051610681916005840191602090910190610ea2565b5060e082015160069091018054610100909301511515600160801b026001600160881b03199093166001600160801b039092169190911791909117905560a081015160c082015160405160019288927f0b927ce548896758f1bc8bb29b6650e47491626f1b708ab99a46412f5322445d926107029291899189908c90611565565b60405180910390a35b5050505050565b6000805b60ff81101561073d576107298382610986565b6107355780915061073d565b600101610716565b50919050565b604080516101208101825260008082526020820181905291810182905260608082018390526080820183905260a0820181905260c082015260e081018290526101008101919091526000838152602081815260408083206001600160801b03861684528252918290208251610120810184528154815260018201548184015260028201546001600160a01b039081168286015260038301549081166060830152600160a01b900463ffffffff1660808201526004820180548551818602810186019096528086529194929360a0860193929083018282801561087457602002820191906000526020600020906000905b82829054906101000a900460ff16600b8111156108525761085261120a565b8152602060019283018181049485019490930390920291018084116108335790505b5050505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b8282101561094e5783829060005260206000200180546108c1906114ce565b80601f01602080910402602001604051908101604052809291908181526020018280546108ed906114ce565b801561093a5780601f1061090f5761010080835404028352916020019161093a565b820191906000526020600020905b81548152906001019060200180831161091d57829003601f168201915b5050505050815260200190600101906108a2565b50505090825250600691909101546001600160801b0381166020830152600160801b900460ff16151560409091015290505b92915050565b6000828152602081815260408083206001600160801b038516845282528083208151610120810183528154815260018201548185015260028201546001600160a01b039081168285015260038301549081166060830152600160a01b900463ffffffff1660808201526004820180548451818702810187019095528085528695929460a086019390929190830182828015610a7057602002820191906000526020600020906000905b82829054906101000a900460ff16600b811115610a4e57610a4e61120a565b815260206001928301818104948501949093039092029101808411610a2f5790505b5050505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b82821015610b4a578382906000526020600020018054610abd906114ce565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae9906114ce565b8015610b365780601f10610b0b57610100808354040283529160200191610b36565b820191906000526020600020905b815481529060010190602001808311610b1957829003601f168201915b505050505081526020019060010190610a9e565b50505090825250600691909101546001600160801b0381166020830152600160801b900460ff161515604090910152805190915015801590610b955750608081015163ffffffff1615155b15610ba4576001915050610980565b6000915050610980565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610bf757604051631bd4dfdf60e01b815260040160405180910390fd5b6000610c0288610712565b9050604051806101200160405280898152602001888152602001876001600160a01b03168152602001866001600160a01b031681526020018563ffffffff168152602001848152602001838152602001826001600160801b03168152602001600015158152506000808a81526020019081526020016000206000836001600160801b03168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a0820151816004019080519060200190610d45929190610dee565b5060c08201518051610d61916005840191602090910190610ea2565b5060e082015160069091018054610100909301511515600160801b026001600160881b03199093166001600160801b039092169190911791909117905560405188907fd44739c3e4748444a6d47fdca8f41581159e21e0a7b0ccc81e492a4ae67b5f2590610ddc908a908a908a908a908a908a908a906115ce565b60405180910390a25050505050505050565b82805482825590600052602060002090601f01602090048101928215610e925791602002820160005b83821115610e6357835183826101000a81548160ff0219169083600b811115610e4257610e4261120a565b02179055509260200192600101602081600001049283019260010302610e17565b8015610e905782816101000a81549060ff0219169055600101602081600001049283019260010302610e63565b505b50610e9e929150610ef4565b5090565b828054828255906000526020600020908101928215610ee8579160200282015b82811115610ee85782518290610ed8908261168b565b5091602001919060010190610ec2565b50610e9e929150610f09565b5b80821115610e9e5760008155600101610ef5565b80821115610e9e576000610f1d8282610f26565b50600101610f09565b508054610f32906114ce565b6000825580601f10610f42575050565b601f016020900490600052602060002090810190610f609190610ef4565b50565b80356001600160801b0381168114610f7a57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610fbe57610fbe610f7f565b604052919050565b600067ffffffffffffffff821115610fe057610fe0610f7f565b5060051b60200190565b600082601f830112610ffb57600080fd5b8135602061101061100b83610fc6565b610f95565b82815260059290921b8401810191818101908684111561102f57600080fd5b8286015b84811015611058578035600c811061104b5760008081fd5b8352918301918301611033565b509695505050505050565b6000601f838184011261107557600080fd5b8235602061108561100b83610fc6565b82815260059290921b850181019181810190878411156110a457600080fd5b8287015b8481101561113b57803567ffffffffffffffff808211156110c95760008081fd5b818a0191508a603f8301126110de5760008081fd5b858201356040828211156110f4576110f4610f7f565b611105828b01601f19168901610f95565b92508183528c8183860101111561111c5760008081fd5b81818501898501375060009082018701528452509183019183016110a8565b50979650505050505050565b6000806000806080858703121561115d57600080fd5b8435935061116d60208601610f63565b9250604085013567ffffffffffffffff8082111561118a57600080fd5b61119688838901610fea565b935060608701359150808211156111ac57600080fd5b506111b987828801611063565b91505092959194509250565b6000602082840312156111d757600080fd5b5035919050565b600080604083850312156111f157600080fd5b8235915061120160208401610f63565b90509250929050565b634e487b7160e01b600052602160045260246000fd5b6000600c821061124057634e487b7160e01b600052602160045260246000fd5b50815260200190565b600081518084526020808501945080840160005b8381101561127e57611270878351611220565b96509082019060010161125d565b509495945050505050565b600081518084526020808501808196508360051b810191508286016000805b86811015611309578385038a5282518051808752835b818110156112d9578281018901518882018a015288016112be565b818111156112e9578489838a0101525b509a87019a601f01601f19169590950186019450918501916001016112a8565b509298975050505050505050565b6020815281516020820152602082015160408201526000604083015161134860608401826001600160a01b03169052565b5060608301516001600160a01b038116608084015250608083015163ffffffff811660a08401525060a08301516101208060c085015261138c610140850183611249565b915060c0850151601f198584030160e08601526113a98382611289565b92505060e08501516101006113c8818701836001600160801b03169052565b90950151151593019290925250919050565b80356001600160a01b0381168114610f7a57600080fd5b600080600080600080600060e0888a03121561140c57600080fd5b8735965060208801359550611423604089016113da565b9450611431606089016113da565b9350608088013563ffffffff8116811461144a57600080fd5b925060a088013567ffffffffffffffff8082111561146757600080fd5b6114738b838c01610fea565b935060c08a013591508082111561148957600080fd5b506114968a828b01611063565b91505092959891949750929550565b6000602082840312156114b757600080fd5b815180151581146114c757600080fd5b9392505050565b600181811c908216806114e257607f821691505b60208210810361073d57634e487b7160e01b600052602260045260246000fd5b600081518084526020808501945080840160005b8381101561127e57611529878351611220565b965090820190600101611516565b60408152600061154a6040830185611502565b828103602084015261155c8185611289565b95945050505050565b60a08152600061157860a0830188611502565b828103602084015261158a8188611502565b9050828103604084015261159e8187611289565b905082810360608401526115b28186611289565b9150506001600160801b03831660808301529695505050505050565b8781526001600160a01b0387811660208301528616604082015263ffffffff8516606082015260e06080820181905260009061160c90830186611502565b82810360a084015261161e8186611289565b9150506001600160801b03831660c083015298975050505050505050565b601f82111561168657600081815260208120601f850160051c810160208610156116635750805b601f850160051c820191505b818110156116825782815560010161166f565b5050505b505050565b815167ffffffffffffffff8111156116a5576116a5610f7f565b6116b9816116b384546114ce565b8461163c565b602080601f8311600181146116ee57600084156116d65750858301515b600019600386901b1c1916600185901b178555611682565b600085815260208120601f198616915b8281101561171d578886015182559484019460019091019084016116fe565b508582101561173b5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea26469706673582212205d5e946ee46c8ef7c662a2c5b67e0091b28cb9005fb54c720e57fa60e218121164736f6c634300080f00330000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000011984dc4465481512eb5b777e44061c158cf225900000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a
Deployed Bytecode
0x6080604052600436106101235760003560e01c80637270bdb0116100a0578063e63ab1e911610064578063e63ab1e91461041e578063f4200a1414610452578063fb1bb9de14610486578063fd614f41146104ba578063ffd864d3146104e757610173565b80637270bdb014610343578063a3fb20f414610363578063a680125814610376578063c80916d4146103b6578063de4b0548146103ea57610173565b80633fb9a94e116100e75780633fb9a94e14610246578063490b48f8146102595780634aa4a4fc1461028d5780635955003c146102d957806363a560ec1461030f57610173565b8063087de6f71461018c5780631163b2b0146101ac57806316d8887a146101cc5780632424401f14610213578063258836fe1461022657610173565b3661017357336001600160a01b037f0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6191614610171576040516372643aad60e01b815260040160405180910390fd5b005b60405163c6a579c760e01b815260040160405180910390fd5b34801561019857600080fd5b506101716101a7366004613582565b61051b565b3480156101b857600080fd5b506101716101c73660046135b2565b61064b565b3480156101d857600080fd5b506102007f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1681565b6040519081526020015b60405180910390f35b6101716102213660046135d6565b610723565b34801561023257600080fd5b506101716102413660046135ef565b6107a2565b610171610254366004613668565b6108e6565b34801561026557600080fd5b506102007fccc64574297998b6c3edf6078cc5e01268465ff116954e3af02ff3a70a730f4681565b34801561029957600080fd5b506102c17f0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61981565b6040516001600160a01b03909116815260200161020a565b3480156102e557600080fd5b506102c16102f43660046135d6565b6003602052600090815260409020546001600160a01b031681565b34801561031b57600080fd5b506102007f3fc733b4d20d27a28452ddf0e9351aced28242fe03389a653cdb783955316b9b81565b34801561034f57600080fd5b5061017161035e3660046136e9565b610956565b610171610371366004613717565b610a13565b34801561038257600080fd5b506103a66103913660046135b2565b60006020819052908152604090205460ff1681565b604051901515815260200161020a565b3480156103c257600080fd5b506102c17f0000000000000000000000007120ca5366d8452d106b56ddd99576a78fa35a1181565b3480156103f657600080fd5b506102c17f00000000000000000000000011984dc4465481512eb5b777e44061c158cf225981565b34801561042a57600080fd5b506102007f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b34801561045e57600080fd5b506102007fe9e995cadb4a71c3f5032f9fbf95a1e1369b940625a86946b14b2d845bf747ab81565b34801561049257600080fd5b506102007f427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a81565b3480156104c657600080fd5b506104da6104d5366004613845565b610a63565b60405161020a919061392c565b3480156104f357600080fd5b506102c17f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a81565b7f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a6001600160a01b031663d33219b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059d919061393f565b6001600160a01b0316336001600160a01b0316146105ce5760405163b909292960e01b815260040160405180910390fd5b6001600160a01b0381166105f55760405163388732eb60e01b815260040160405180910390fd5b60008281526003602052604080822080546001600160a01b0319166001600160a01b038516908117909155905184927f038088a234c0d1d17a5f4c755e87c5283845155cf3344f6c977eedca1275ef1591a35050565b604051632474521560e21b81527fe9e995cadb4a71c3f5032f9fbf95a1e1369b940625a86946b14b2d845bf747ab60048201523360248201527f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a6001600160a01b0316906391d1485490604401602060405180830381865afa1580156106d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f9919061395c565b61071657604051639c73fc7f60e01b815260040160405180910390fd5b6107208147610db2565b50565b604051632424401f60e01b8152600481018290527f00000000000000000000000011984dc4465481512eb5b777e44061c158cf22596001600160a01b031690632424401f9034906024016000604051808303818588803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b505050505050565b604051632474521560e21b81527fe9e995cadb4a71c3f5032f9fbf95a1e1369b940625a86946b14b2d845bf747ab60048201523360248201527f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a6001600160a01b0316906391d1485490604401602060405180830381865afa15801561082c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610850919061395c565b61086d57604051639c73fc7f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526108e290839083906001600160a01b038316906370a0823190602401602060405180830381865afa1580156108b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dd9190613979565b610e45565b5050565b33301461090657604051633228cc7160e21b815260040160405180910390fd5b61094f85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061094992508691508790506139b5565b83610ea8565b5050505050565b7f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a6001600160a01b031663d33219b46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d8919061393f565b6001600160a01b0316336001600160a01b031614610a095760405163b909292960e01b815260040160405180910390fd5b6108e28282611a16565b610a5d848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a5692508591508690506139b5565b6000610ea8565b50505050565b606060008083806020019051810190610a7c9190613b60565b90925090506000808915610bc9576040516370a0823160e01b81523060048201526001600160a01b038a16906370a0823190602401602060405180830381865afa158015610ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af29190613979565b915089821015610b155760405163018884f160e51b815260040160405180910390fd5b60405180604001604052808a6001600160a01b031681526020018b84610b3b9190613bd9565b90528051600180546001600160a01b039092166001600160a01b031990921691909117905560200151600255610ba68a85600081518110610b7e57610b7e613bf0565b602002602001015185600081518110610b9957610b99613bf0565b6020026020010151611adf565b84600081518110610bb957610bb9613bf0565b6020026020010181935082905250505b604051631fdcd4a760e11b81523090633fb9a94e90610bf090879087908690600401613cca565b600060405180830381600087803b158015610c0a57600080fd5b505af1925050508015610c1b575060015b610d4d578115610cdb57610c50897f0000000000000000000000007120ca5366d8452d106b56ddd99576a78fa35a1184610e45565b60405163e667df2f60e01b81526001600160a01b037f0000000000000000000000007120ca5366d8452d106b56ddd99576a78fa35a11169063e667df2f90610ca8908e908e908e908e908e908c908c90600401613d00565b600060405180830381600087803b158015610cc257600080fd5b505af1158015610cd6573d6000803e3d6000fd5b505050505b6001600080820160006101000a8154906001600160a01b030219169055600182016000905550508663ffffffff168b7f62277c9bd483b2bd832cf3849e52ec0a2b1e4297f133ccb28e963239a8007f5a60008c8e8b604051610d409493929190613d65565b60405180910390a3610d94565b8663ffffffff168b7f62277c9bd483b2bd832cf3849e52ec0a2b1e4297f133ccb28e963239a8007f5a60018c8e8b604051610d8b9493929190613d65565b60405180910390a35b50506040805160208101909152600081529998505050505050505050565b604080516000808252602082019092526001600160a01b038416908390604051610ddc9190613d9e565b60006040518083038185875af1925050503d8060008114610e19576040519150601f19603f3d011682016040523d82523d6000602084013e610e1e565b606091505b5050905080610e40576040516322462d1f60e01b815260040160405180910390fd5b505050565b6040516001600160a01b038316602482015260448101829052610e4090849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611c0d565b825182518114610ecb576040516305b9af8f60e51b815260040160405180910390fd5b60408051600a808252610160820190925260009182918291816020015b6040805180820190915260008082526020820152815260200190600190039081610ee85750506001549091506001600160a01b031615610f6157604080518082019091526001546001600160a01b03168152600254602082015281518290600090610f5557610f55613bf0565b60200260200101819052505b6000610f6d3447613bd9565b905060005b85811015611a01576000898281518110610f8e57610f8e613bf0565b602002602001015190506000600b811115610fab57610fab613c06565b81600b811115610fbd57610fbd613c06565b03611119576000806000808c8681518110610fda57610fda613bf0565b6020026020010151806020019051810190610ff59190613dba565b935093509350935061100684611ce7565b6000846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106a919061393f565b90506110768b84611d8e565b9a50611082818a611de0565b985061108f818386611eb9565b61109a818686611eeb565b604051636e553f6560e01b8152600481018590526001600160a01b038481166024830152861690636e553f65906044015b6020604051808303816000875af11580156110ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110e9190613979565b5050505050506119f8565b600181600b81111561112d5761112d613c06565b03611277576000806000808c868151811061114a5761114a613bf0565b60200260200101518060200190518101906111659190613dba565b935093509350935061117684611ce7565b6111808a82611d8e565b99506111ed846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e7919061393f565b89611de0565b604051632d182be560e21b8152600481018590526001600160a01b03848116602483015283811660448301529199509085169063b460af94906064015b6020604051808303816000875af1158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d9190613979565b50505050506119f8565b600281600b81111561128b5761128b613c06565b03611362576000806000808c86815181106112a8576112a8613bf0565b60200260200101518060200190518101906112c39190613dba565b93509350935093506112d484611ce7565b6112de8a82611d8e565b9950611321846001600160a01b031663a919802d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c3573d6000803e3d6000fd5b604051633545906160e21b8152600481018590526001600160a01b03848116602483015283811660448301529199509085169063d51641849060640161122a565b600381600b81111561137657611376613c06565b03611488576000806000808c868151811061139357611393613bf0565b60200260200101518060200190518101906113ae9190613dba565b93509350935093506113bf84611ce7565b6000846001600160a01b031663a919802d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611423919061393f565b905061142f8b84611d8e565b9a5061143b818a611de0565b9850611448818386611eb9565b611453818686611eeb565b60405163d084b9af60e01b8152600481018590526001600160a01b03848116602483015286169063d084b9af906044016110cb565b600681600b81111561149c5761149c613c06565b036114ee57846114b4576114b18a8a8a611ef6565b94505b60006114da828b85815181106114cc576114cc613bf0565b602002602001015188612221565b90506114e68782611d8e565b9650506119f8565b600781600b81111561150257611502613c06565b0361151757846114b4576114b18a8a8a611ef6565b600881600b81111561152b5761152b613c06565b0361155a5761155389838151811061154557611545613bf0565b6020026020010151876123f8565b95506119f8565b600981600b81111561156e5761156e613c06565b036115965761155389838151811061158857611588613bf0565b6020026020010151876125a2565b600581600b8111156115aa576115aa613c06565b036115fe57816000036115d05760405163b42fccab60e01b815260040160405180910390fd5b6115f48983815181106115e5576115e5613bf0565b60200260200101518786612765565b90965093506119f8565b600481600b81111561161257611612613c06565b036117e65760008060008060008d878151811061163157611631613bf0565b602002602001015180602001905181019061164c9190613e0f565b6040516306a33c7960e51b81526001600160a01b038681166004830152959a50939850919650945092507f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a9091169063d4678f2090602401602060405180830381865afa1580156116c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e5919061395c565b61170257604051631ddd578f60e11b815260040160405180910390fd5b6001600160a01b038216301461172b5760405163ef34858960e01b815260040160405180910390fd5b611735848a611de0565b985060008061175283600480865161174d9190613bd9565b6129df565b8060200190518101906117659190613b60565b915091506117738282612aec565b604051631f8aa39560e21b8152909d506001600160a01b03881690637e2a8e54906117a8908990899089908990600401613e90565b600060405180830381600087803b1580156117c257600080fd5b505af11580156117d6573d6000803e3d6000fd5b50505050505050505050506119f8565b600a81600b8111156117fa576117fa613c06565b036118eb57600089838151811061181357611813613bf0565b602002602001015180602001905181019061182e9190613979565b9050348114611850576040516379eecdfb60e11b815260040160405180910390fd5b61187a7f0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61986611de0565b94507f0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6196001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156118d757600080fd5b505af115801561110e573d6000803e3d6000fd5b600b81600b8111156118ff576118ff613c06565b036119f8576000808a848151811061191957611919613bf0565b60200260200101518060200190518101906119349190613ec3565b915091506119428882611d8e565b975061196e7f0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61987611de0565b604051632e1a7d4d60e01b8152600481018490529096507f0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6196001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156119d357600080fd5b505af11580156119e7573d6000803e3d6000fd5b505050506119f58183610db2565b50505b50600101610f72565b50611a0c82826130ef565b5050505050505050565b6001600160a01b038216611a3d57604051632cdf6c4b60e11b815260040160405180910390fd5b6001600160a01b03821660009081526020819052604090205481151560ff909116151503611a7e576040516332fe3f1960e21b815260040160405180910390fd5b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f6bf208b256dacdc89831fd5124ada2aa0f56252c178dd5aff85ee68daf0a7f1c910160405180910390a15050565b8060008084600b811115611af557611af5613c06565b1480611b125750600384600b811115611b1057611b10613c06565b145b15611b8d5760008060008086806020019051810190611b319190613dba565b9350935093509350888314611b8457604080516001600160a01b0380871660208301529181018b905281841660608201529082166080820152929450849260a00160405160208183030381529060405295505b50505050611c05565b600b84600b811115611ba157611ba1613c06565b03611c055760008084806020019051810190611bbd9190613ec3565b91509150868214611c02578192508681604051602001611bf09291909182526001600160a01b0316602082015260400190565b60405160208183030381529060405293505b50505b935093915050565b6000611c62826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661322c9092919063ffffffff16565b9050805160001480611c83575080806020019051810190611c83919061395c565b610e405760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b604051630c5aed5760e01b81526001600160a01b0382811660048301527f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a1690630c5aed5790602401602060405180830381865afa158015611d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d71919061395c565b6107205760405163106f25d560e31b815260040160405180910390fd5b60006001600160a01b038316611da5575080611dda565b816001600160a01b0316836001600160a01b031614611dd757604051630727952560e41b815260040160405180910390fd5b50805b92915050565b6060600080611def8585613243565b9150915081611eb05760008115611e1057611e0b826001613ee8565b611e12565b815b6040805180820182526001600160a01b03891680825291516370a0823160e01b8152306004820152929350916020830191906370a0823190602401602060405180830381865afa158015611e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8e9190613979565b815250858281518110611ea357611ea3613bf0565b6020026020010181905250505b50919392505050565b6001600160a01b0382163014801590611eda57506001600160a01b03821633145b15610e4057610e40838330846132a7565b610e408383836132df565b825160009081816001600160401b03811115611f1457611f14613782565b604051908082528060200260200182016040528015611f4757816020015b6060815260200190600190039081611f325790505b50905060005b828110156121ec57858181518110611f6757611f67613bf0565b6020026020010151828281518110611f8157611f81613bf0565b6020026020010181905250806000148015611f9b57508415155b801561200557506000878281518110611fb657611fb6613bf0565b6020026020010151600b811115611fcf57611fcf613c06565b148061200557506003878281518110611fea57611fea613bf0565b6020026020010151600b81111561200357612003613c06565b145b156120ab5760008060008085858151811061202257612022613bf0565b602002602001015180602001905181019061203d9190613dba565b93509350935093508289146120a657604080516001600160a01b0380871660208301529181018b90528184166060820152908216608082015260a00160405160208183030381529060405286868151811061209a5761209a613bf0565b60200260200101819052505b505050505b60068782815181106120bf576120bf613bf0565b6020026020010151600b8111156120d8576120d8613c06565b148061210e575060078782815181106120f3576120f3613bf0565b6020026020010151600b81111561210c5761210c613c06565b145b156121da5760008060008085858151811061212b5761212b613bf0565b60200260200101518060200190518101906121469190613f00565b5050604080516001600160a01b038089166020830152808816828401528616606082015260808101859052600060a0820181905260c0820181905260e08201819052610100808301919091528251808303909101815261012090910190915295995093975091955093506121b8915050565b8686815181106121ca576121ca613bf0565b6020026020010181905250505050505b806121e481613f8c565b915050611f4d565b508581604051602001612200929190613fa5565b60405160208183030381529060405280519060200120925050509392505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052838060200190518101906122759190613f00565b60e089015260c088015260ff1660a0870152608086015260608501526001600160a01b0390811660408501529081166020840152168082526122b690611ce7565b600685600b8111156122ca576122ca613c06565b036123605780600001516001600160a01b0316630fad31318260200151836040015184606001518560800151888760a001518860c001518960e001516040518963ffffffff1660e01b8152600401612329989796959493929190613fd3565b600060405180830381600087803b15801561234357600080fd5b505af1158015612357573d6000803e3d6000fd5b505050506123ec565b600785600b81111561237457612374613c06565b036123d35780600001516001600160a01b03166396ebbc458260200151836040015184606001518560800151888760a001518860c001518960e001516040518963ffffffff1660e01b8152600401612329989796959493929190613fd3565b604051632f67478960e21b815260040160405180910390fd5b60200151949350505050565b600080600080600080600088806020019051810190612417919061401a565b955095509550955095509550600061242f8984611d8e565b905061243c858386611eb9565b612467857f00000000000000000000000011984dc4465481512eb5b777e44061c158cf225986611eeb565b6040516345560b5d60e11b815263ffffffff881660048201526001600160a01b038481166024830152868116604483015282811660648301526084820186905260a4820188905260e060c4830152600060e48301819052917f00000000000000000000000011984dc4465481512eb5b777e44061c158cf225990911690638aac16ba90610104016020604051808303816000875af115801561250d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125319190613979565b604080518a81526001600160a01b038981166020830152918101889052608060608201819052600090820152919250851690339083907fb7c6eb876c99dadc81a4df296037aa08e5c6be07a3765524cf8812aec701f7e49060a00160405180910390a4509998505050505050505050565b6000806000806000806000888060200190518101906125c19190614083565b955095509550955095509550600080828060200190518101906125e491906140f5565b50915091506125fc8a6125f78484612aec565b611d8e565b9850612609868587611eb9565b612634867f00000000000000000000000011984dc4465481512eb5b777e44061c158cf225987611eeb565b60007f00000000000000000000000011984dc4465481512eb5b777e44061c158cf22596001600160a01b0316638aac16ba8a600360008d815260200190815260200160002060009054906101000a90046001600160a01b03168a8e8b8e8b6040518863ffffffff1660e01b81526004016126b49796959493929190614161565b6020604051808303816000875af11580156126d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f79190613979565b60008a815260036020526040908190205490519192506001600160a01b031690339083907fb7c6eb876c99dadc81a4df296037aa08e5c6be07a3765524cf8812aec701f7e49061274e908e908d908d908c906141bc565b60405180910390a450505050505050505092915050565b600060606000806000806000806000808c80602001905181019061278991906141e9565b975097509750975097509750975097507f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a6001600160a01b031663877945f0896040518263ffffffff1660e01b81526004016127f491906001600160a01b0391909116815260200190565b602060405180830381865afa158015612811573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612835919061395c565b6128525760405163418f824160e01b815260040160405180910390fd5b61285c878c611de0565b9a50612868868c611de0565b9a50612875878987611eeb565b6001600160a01b038316301480159061291557506040516306a33c7960e51b81526001600160a01b0384811660048301527f00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a169063d4678f2090602401602060405180830381865afa1580156128ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612913919061395c565b155b15612927576129248c84611d8e565b9b505b6001600160a01b0382163014612944576129418c83611d8e565b9b505b60405163e2c4f23b60e01b81526001600160a01b03888116600483015287811660248301526044820187905260648201869052848116608483015283811660a483015260c4820183905289169063e2c4f23b9060e401600060405180830381600087803b1580156129b457600080fd5b505af11580156129c8573d6000803e3d6000fd5b509d9f9c9e509b9c50505050505050505050505050565b6060816129ed81601f613ee8565b1015612a2c5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401611cde565b612a368284613ee8565b84511015612a7a5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401611cde565b606082158015612a995760405191506000825260208201604052612ae3565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612ad2578051835260209283019201612aba565b5050858452601f01601f1916604052505b50949350505050565b60008083600081518110612b0257612b02613bf0565b6020026020010151600b811115612b1b57612b1b613c06565b1480612b525750600383600081518110612b3757612b37613bf0565b6020026020010151600b811115612b5057612b50613c06565b145b15612b9357600082600081518110612b6c57612b6c613bf0565b6020026020010151806020019051810190612b879190613dba565b509350611dda92505050565b600183600081518110612ba857612ba8613bf0565b6020026020010151600b811115612bc157612bc1613c06565b1480612bf85750600283600081518110612bdd57612bdd613bf0565b6020026020010151600b811115612bf657612bf6613c06565b145b15612c3957600082600081518110612c1257612c12613bf0565b6020026020010151806020019051810190612c2d9190613dba565b9450611dda9350505050565b600b83600081518110612c4e57612c4e613bf0565b6020026020010151600b811115612c6757612c67613c06565b03612ca657600082600081518110612c8157612c81613bf0565b6020026020010151806020019051810190612c9c9190613ec3565b9250611dda915050565b600783600081518110612cbb57612cbb613bf0565b6020026020010151600b811115612cd457612cd4613c06565b1480612d0b5750600683600081518110612cf057612cf0613bf0565b6020026020010151600b811115612d0957612d09613c06565b145b15612d5157600082600081518110612d2557612d25613bf0565b6020026020010151806020019051810190612d409190613f00565b50949750611dda9650505050505050565b600483600081518110612d6657612d66613bf0565b6020026020010151600b811115612d7f57612d7f613c06565b03612dfb57600082600081518110612d9957612d99613bf0565b6020026020010151806020019051810190612db49190613e0f565b945050505050600080612dd083600480865161174d9190613bd9565b806020019051810190612de39190613b60565b91509150612df18282612aec565b9350505050611dda565b600883600081518110612e1057612e10613bf0565b6020026020010151600b811115612e2957612e29613c06565b03612e6c57600082600081518110612e4357612e43613bf0565b6020026020010151806020019051810190612e5e919061401a565b509550611dda945050505050565b600983600081518110612e8157612e81613bf0565b6020026020010151600b811115612e9a57612e9a613c06565b03612efb57600082600081518110612eb457612eb4613bf0565b6020026020010151806020019051810190612ecf919061427c565b94505050505060008082806020019051810190612eec91906140f5565b5091509150612df18282612aec565b600a83600081518110612f1057612f10613bf0565b6020026020010151600b811115612f2957612f29613c06565b036130a35782516000612f3d600183613bd9565b6001600160401b03811115612f5457612f54613782565b604051908082528060200260200182016040528015612f7d578160200160208202803683370190505b5090506000612f8d600184613bd9565b6001600160401b03811115612fa457612fa4613782565b604051908082528060200260200182016040528015612fd757816020015b6060815260200190600190039081612fc25790505b50905060015b8381101561309857868181518110612ff757612ff7613bf0565b60200260200101518360018361300d9190613bd9565b8151811061301d5761301d613bf0565b6020026020010190600b81111561303657613036613c06565b9081600b81111561304957613049613c06565b8152505085818151811061305f5761305f613bf0565b6020026020010151826001836130759190613bd9565b8151811061308557613085613bf0565b6020908102919091010152600101612fdd565b50612df18282612aec565b6005836000815181106130b8576130b8613bf0565b6020026020010151600b8111156130d1576130d1613c06565b03611dda5760405163b42fccab60e01b815260040160405180910390fd5b815160005b8181101561320b5760006001600160a01b031684828151811061311957613119613bf0565b6020026020010151600001516001600160a01b03161461320357600084828151811061314757613147613bf0565b6020026020010151602001519050600085838151811061316957613169613bf0565b6020908102919091010151516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156131ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131de9190613979565b905081811461320057604051632c1b2f5f60e21b815260040160405180910390fd5b50505b6001016130f4565b50478214610e4057604051632c1b2f5f60e21b815260040160405180910390fd5b606061323b84846000856133f4565b949350505050565b80516000908190815b8181101561329e5784818151811061326657613266613bf0565b6020026020010151600001516001600160a01b0316866001600160a01b031603613296576001935080925061329e565b60010161324c565b50509250929050565b6040516001600160a01b0380851660248301528316604482015260648101829052610a5d9085906323b872dd60e01b90608401610e71565b8015806133595750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613333573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133579190613979565b155b6133c45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401611cde565b6040516001600160a01b038316602482015260448101829052610e4090849063095ea7b360e01b90606401610e71565b6060824710156134555760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611cde565b600080866001600160a01b031685876040516134719190613d9e565b60006040518083038185875af1925050503d80600081146134ae576040519150601f19603f3d011682016040523d82523d6000602084013e6134b3565b606091505b50915091506134c4878383876134cf565b979650505050505050565b6060831561353e578251600003613537576001600160a01b0385163b6135375760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611cde565b508161323b565b61323b83838151156135535781518083602001fd5b8060405162461bcd60e51b8152600401611cde919061392c565b6001600160a01b038116811461072057600080fd5b6000806040838503121561359557600080fd5b8235915060208301356135a78161356d565b809150509250929050565b6000602082840312156135c457600080fd5b81356135cf8161356d565b9392505050565b6000602082840312156135e857600080fd5b5035919050565b6000806040838503121561360257600080fd5b823561360d8161356d565b915060208301356135a78161356d565b60008083601f84011261362f57600080fd5b5081356001600160401b0381111561364657600080fd5b6020830191508360208260051b850101111561366157600080fd5b9250929050565b60008060008060006060868803121561368057600080fd5b85356001600160401b038082111561369757600080fd5b6136a389838a0161361d565b909750955060208801359150808211156136bc57600080fd5b506136c98882890161361d565b96999598509660400135949350505050565b801515811461072057600080fd5b600080604083850312156136fc57600080fd5b82356137078161356d565b915060208301356135a7816136db565b6000806000806040858703121561372d57600080fd5b84356001600160401b038082111561374457600080fd5b6137508883890161361d565b9096509450602087013591508082111561376957600080fd5b506137768782880161361d565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156137c0576137c0613782565b604052919050565b60006001600160401b038211156137e1576137e1613782565b50601f01601f191660200190565b600082601f83011261380057600080fd5b813561381361380e826137c8565b613798565b81815284602083860101111561382857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561385e57600080fd5b863595506020870135945060408701356138778161356d565b935060608701356138878161356d565b9250608087013563ffffffff811681146138a057600080fd5b915060a08701356001600160401b038111156138bb57600080fd5b6138c789828a016137ef565b9150509295509295509295565b60005b838110156138ef5781810151838201526020016138d7565b83811115610a5d5750506000910152565b600081518084526139188160208601602086016138d4565b601f01601f19169290920160200192915050565b6020815260006135cf6020830184613900565b60006020828403121561395157600080fd5b81516135cf8161356d565b60006020828403121561396e57600080fd5b81516135cf816136db565b60006020828403121561398b57600080fd5b5051919050565b60006001600160401b038211156139ab576139ab613782565b5060051b60200190565b60006139c361380e84613992565b80848252602080830192508560051b8501368111156139e157600080fd5b855b81811015613a1c5780356001600160401b03811115613a025760008081fd5b613a0e36828a016137ef565b8652509382019382016139e3565b50919695505050505050565b600082601f830112613a3957600080fd5b81516020613a4961380e83613992565b82815260059290921b84018101918181019086841115613a6857600080fd5b8286015b84811015613a91578051600c8110613a845760008081fd5b8352918301918301613a6c565b509695505050505050565b600082601f830112613aad57600080fd5b8151613abb61380e826137c8565b818152846020838601011115613ad057600080fd5b61323b8260208301602087016138d4565b600082601f830112613af257600080fd5b81516020613b0261380e83613992565b82815260059290921b84018101918181019086841115613b2157600080fd5b8286015b84811015613a915780516001600160401b03811115613b445760008081fd5b613b528986838b0101613a9c565b845250918301918301613b25565b60008060408385031215613b7357600080fd5b82516001600160401b0380821115613b8a57600080fd5b613b9686838701613a28565b93506020850151915080821115613bac57600080fd5b50613bb985828601613ae1565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b600082821015613beb57613beb613bc3565b500390565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60008151808452602080850194508084016000805b84811015613c69578251600c8110613c5757634e487b7160e01b83526021600452602483fd5b88529683019691830191600101613c31565b50959695505050505050565b600081518084526020808501808196508360051b8101915082860160005b85811015613cbd578284038952613cab848351613900565b98850198935090840190600101613c93565b5091979650505050505050565b606081526000613cdd6060830186613c1c565b8281036020840152613cef8186613c75565b915050826040830152949350505050565b878152602081018790526001600160a01b0386811660408301528516606082015263ffffffff8416608082015260e060a08201819052600090613d4590830185613c1c565b82810360c0840152613d578185613c75565b9a9950505050505050505050565b841515815260018060a01b0384166020820152826040820152608060608201526000613d946080830184613900565b9695505050505050565b60008251613db08184602087016138d4565b9190910192915050565b60008060008060808587031215613dd057600080fd5b8451613ddb8161356d565b602086015160408701519195509350613df38161356d565b6060860151909250613e048161356d565b939692955090935050565b600080600080600060a08688031215613e2757600080fd5b8551613e328161356d565b6020870151909550613e438161356d565b604087015160608801519195509350613e5b8161356d565b60808701519092506001600160401b03811115613e7757600080fd5b613e8388828901613a9c565b9150509295509295909350565b6001600160a01b0385811682526020820185905283166040820152608060608201819052600090613d9490830184613900565b60008060408385031215613ed657600080fd5b8251915060208301516135a78161356d565b60008219821115613efb57613efb613bc3565b500190565b600080600080600080600080610100898b031215613f1d57600080fd5b8851613f288161356d565b60208a0151909850613f398161356d565b60408a0151909750613f4a8161356d565b80965050606089015194506080890151935060a089015160ff81168114613f7057600080fd5b60c08a015160e0909a0151989b979a5095989497939692505050565b600060018201613f9e57613f9e613bc3565b5060010190565b604081526000613fb86040830185613c1c565b8281036020840152613fca8185613c75565b95945050505050565b6001600160a01b03988916815296909716602087015260408601949094526060850192909252608084015260ff1660a083015260c082015260e08101919091526101000190565b60008060008060008060c0878903121561403357600080fd5b8651955060208701519450604087015161404c8161356d565b6060880151608089015191955093506140648161356d565b60a08801519092506140758161356d565b809150509295509295509295565b60008060008060008060c0878903121561409c57600080fd5b865195506020870151945060408701516140b58161356d565b6060880151608089015191955093506140cd8161356d565b60a08801519092506001600160401b038111156140e957600080fd5b6138c789828a01613a9c565b60008060006060848603121561410a57600080fd5b83516001600160401b038082111561412157600080fd5b61412d87838801613a28565b9450602086015191508082111561414357600080fd5b5061415086828701613ae1565b925050604084015190509250925092565b63ffffffff881681526001600160a01b0387811660208301528681166040830152851660608201526080810184905260a0810183905260e060c082018190526000906141af90830184613900565b9998505050505050505050565b84815260018060a01b0384166020820152826040820152608060608201526000613d946080830184613900565b600080600080600080600080610100898b03121561420657600080fd5b88516142118161356d565b60208a01519098506142228161356d565b60408a01519097506142338161356d565b80965050606089015194506080890151935060a08901516142538161356d565b60c08a01519093506142648161356d565b8092505060e089015190509295985092959890939650565b600080600080600060a0868803121561429457600080fd5b855194506020860151935060408601516142ad8161356d565b6060870151608088015191945092506001600160401b03811115613e7757600080fdfea2646970667358221220895d0472be94d1dce0b168504cb164620e17c452cff2b751dc482ac28487208264736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000011984dc4465481512eb5b777e44061c158cf225900000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a
-----Decoded View---------------
Arg [0] : weth (address): 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619
Arg [1] : connext_ (address): 0x11984dc4465481512eb5b777E44061C158CF2259
Arg [2] : chief (address): 0x69097538190AC1bceAa0C8ebFA7C512b1eb8D24a
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f619
Arg [1] : 00000000000000000000000011984dc4465481512eb5b777e44061c158cf2259
Arg [2] : 00000000000000000000000069097538190ac1bceaa0c8ebfa7c512b1eb8d24a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.