Contract Overview
Balance:
0 MATIC
MATIC Value:
$0.00
My Name Tag:
Not Available, login to update
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x92c4ef2b2f2c312b1074c3a0bf79dedfffb799e0aafcb47a17ae50bef32bead1 | 22551775 | 530 days 12 hrs ago | 0x2fd525b8b2e2a69d054dccb033a0e33e0b4ab370 | Contract Creation | 0 MATIC |
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DiamondCutFacet
Compiler Version
v0.8.7+commit.e28d00a7
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { ILiFi } from "../Interfaces/ILiFi.sol"; import { IAnyswapRouter } from "../Interfaces/IAnyswapRouter.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; import { LibAsset } from "../Libraries/LibAsset.sol"; import { LibSwap } from "../Libraries/LibSwap.sol"; import { IAnyswapToken } from "../Interfaces/IAnyswapToken.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; contract AnyswapFacet is ILiFi { /* ========== Storage ========== */ bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.anyswap"); struct Storage { address anyswapRouter; } /* ========== Types ========== */ struct AnyswapData { address token; uint256 amount; address recipient; uint256 toChainId; } /* ========== Init ========== */ function initAnyswap(address _anyswapRouter) external { Storage storage s = getStorage(); LibDiamond.enforceIsContractOwner(); s.anyswapRouter = _anyswapRouter; } /* ========== Public Bridge Functions ========== */ /** * @notice Bridges tokens via Anyswap * @param _lifiData data used purely for tracking and analytics * @param _anyswapData data specific to Anyswap */ function startBridgeTokensViaAnyswap(LiFiData memory _lifiData, AnyswapData calldata _anyswapData) public payable { if (_anyswapData.token != address(0)) { uint256 _fromTokenBalance = LibAsset.getOwnBalance(_anyswapData.token); address underlyingToken = IAnyswapToken(_anyswapData.token).underlying(); LibAsset.transferFromERC20(underlyingToken, msg.sender, address(this), _anyswapData.amount); require( LibAsset.getOwnBalance(underlyingToken) - _fromTokenBalance == _anyswapData.amount, "ERR_INVALID_AMOUNT" ); } else { require(msg.value == _anyswapData.amount, "ERR_INVALID_AMOUNT"); } _startBridge(_anyswapData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /** * @notice Performs a swap before bridging via Anyswap * @param _lifiData data used purely for tracking and analytics * @param _swapData an array of swap related data for performing swaps before bridging * @param _anyswapData data specific to Anyswap */ function swapAndStartBridgeTokensViaAnyswap( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, AnyswapData calldata _anyswapData ) public payable { if (_anyswapData.token != address(0)) { address underlyingToken = IAnyswapToken(_anyswapData.token).underlying(); uint256 _fromTokenBalance = LibAsset.getOwnBalance(underlyingToken); // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } require( LibAsset.getOwnBalance(underlyingToken) - _fromTokenBalance >= _anyswapData.amount, "ERR_INVALID_AMOUNT" ); } else { uint256 _fromBalance = address(this).balance; // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } require(address(this).balance - _fromBalance >= _anyswapData.amount, "ERR_INVALID_AMOUNT"); } _startBridge(_anyswapData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /* ========== External Config Functions ========== */ /** * @dev Changes address of Anyswap router * @param _newRouter address of the new router */ function changeAnyswapRouter(address _newRouter) external { Storage storage s = getStorage(); LibDiamond.enforceIsContractOwner(); s.anyswapRouter = _newRouter; } /* ========== Internal Functions ========== */ /** * @dev Conatains the business logic for the bridge via Anyswap * @param _anyswapData data specific to Anyswap */ function _startBridge(AnyswapData calldata _anyswapData) internal { Storage storage s = getStorage(); // Check chain id require(block.chainid != _anyswapData.toChainId, "Cannot bridge to the same network."); if (_anyswapData.token != address(0)) { // Give Anyswap approval to bridge tokens LibAsset.approveERC20( IERC20(IAnyswapToken(_anyswapData.token).underlying()), s.anyswapRouter, _anyswapData.amount ); IAnyswapRouter(s.anyswapRouter).anySwapOutUnderlying( _anyswapData.token, _anyswapData.recipient, _anyswapData.amount, _anyswapData.toChainId ); } else { IAnyswapRouter(s.anyswapRouter).anySwapOutNative{ value: _anyswapData.amount }( _anyswapData.token, _anyswapData.recipient, _anyswapData.toChainId ); } } function getStorage() internal pure returns (Storage storage s) { bytes32 namespace = NAMESPACE; // solhint-disable-next-line no-inline-assembly assembly { s.slot := namespace } } }
// SPDX-License-Identifier: MIT 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.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * 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}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * 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 value {ERC20} uses, unless this function is * 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: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, 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}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), 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}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - 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) { _approve(_msgSender(), spender, _allowances[_msgSender()][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) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * 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: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, 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; _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; } _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 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: MIT pragma solidity ^0.8.7; interface ILiFi { /* ========== Structs ========== */ struct LiFiData { bytes32 transactionId; string integrator; address referrer; address sendingAssetId; address receivingAssetId; address receiver; uint256 destinationChainId; uint256 amount; } /* ========== Events ========== */ event LiFiTransferStarted( bytes32 indexed transactionId, string integrator, address referrer, address sendingAssetId, address receivingAssetId, address receiver, uint256 amount, uint256 destinationChainId, uint256 timestamp ); event LiFiTransferCompleted( bytes32 indexed transactionId, address receivingAssetId, address receiver, uint256 amount, uint256 timestamp ); event LiFiTransferConfirmed( bytes32 indexed transactionId, string integrator, address referrer, address sendingAssetId, address receivingAssetId, address receiver, uint256 amount, uint256 destinationChainId, uint256 timestamp ); event LiFiTransferRefunded( bytes32 indexed transactionId, string integrator, address referrer, address sendingAssetId, address receivingAssetId, address receiver, uint256 amount, uint256 destinationChainId, uint256 timestamp ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; interface IAnyswapRouter { function anySwapOutUnderlying( address token, address to, uint256 amount, uint256 toChainID ) external; function anySwapOutNative( address token, address to, uint256 toChainID ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { IDiamondCut } from "../Interfaces/IDiamondCut.sol"; library LibDiamond { bytes32 internal constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); struct FacetAddressAndPosition { address facetAddress; uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array } struct FacetFunctionSelectors { bytes4[] functionSelectors; uint256 facetAddressPosition; // position of facetAddress in facetAddresses array } struct DiamondStorage { // maps function selector to the facet address and // the position of the selector in the facetFunctionSelectors.selectors array mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition; // maps facet addresses to function selectors mapping(address => FacetFunctionSelectors) facetFunctionSelectors; // facet addresses address[] facetAddresses; // Used to query if a contract implements an interface. // Used to implement ERC-165. mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; } function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { ds.slot := position } } event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } function contractOwner() internal view returns (address contractOwner_) { contractOwner_ = diamondStorage().contractOwner; } function enforceIsContractOwner() internal view { require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner"); } event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata); // Internal function version of diamondCut function diamondCut( IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata ) internal { for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) { IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamondCut.FacetCutAction.Add) { addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Replace) { replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Remove) { removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else { revert("LibDiamondCut: Incorrect FacetCutAction"); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists"); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function"); removeFunction(ds, oldFacetAddress, selector); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)"); for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; removeFunction(ds, oldFacetAddress, selector); } } function addFacet(DiamondStorage storage ds, address _facetAddress) internal { enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code"); ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length; ds.facetAddresses.push(_facetAddress); } function addFunction( DiamondStorage storage ds, bytes4 _selector, uint96 _selectorPosition, address _facetAddress ) internal { ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition; ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector); ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress; } function removeFunction( DiamondStorage storage ds, address _facetAddress, bytes4 _selector ) internal { require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist"); // an immutable function is a function defined directly in a diamond require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function"); // replace selector with last selector, then delete last selector uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition; uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1; // if not the same then replace _selector with lastSelector if (selectorPosition != lastSelectorPosition) { bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition]; ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector; ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition); } // delete the last selector ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop(); delete ds.selectorToFacetAndPosition[_selector]; // if no more selectors for facet address then delete the facet address if (lastSelectorPosition == 0) { // replace facet address with last facet address and delete last facet address uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1; uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; if (facetAddressPosition != lastFacetAddressPosition) { address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition]; ds.facetAddresses[facetAddressPosition] = lastFacetAddress; ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition; } ds.facetAddresses.pop(); delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; } } function initializeDiamondCut(address _init, bytes memory _calldata) internal { if (_init == address(0)) { require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty"); } else { require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)"); if (_init != address(this)) { enforceHasContractCode(_init, "LibDiamondCut: _init address has no code"); } // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up the error revert(string(error)); } else { revert("LibDiamondCut: _init function reverted"); } } } } function enforceHasContractCode(address _contract, string memory _errorMessage) internal view { uint256 contractSize; // solhint-disable-next-line no-inline-assembly assembly { contractSize := extcodesize(_contract) } require(contractSize > 0, _errorMessage); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title LibAsset * @author Connext <[email protected]> * @notice This library contains helpers for dealing with onchain transfers * of assets, including accounting for the native asset `assetId` * conventions and any noncompliant ERC20 transfers */ library LibAsset { /** * @dev All native assets use the empty address for their asset id * by convention */ address internal constant NATIVE_ASSETID = address(0); /** * @notice Determines whether the given assetId is the native asset * @param assetId The asset identifier to evaluate * @return Boolean indicating if the asset is the native asset */ function isNativeAsset(address assetId) internal pure returns (bool) { return assetId == NATIVE_ASSETID; } /** * @notice Gets the balance of the inheriting contract for the given asset * @param assetId The asset identifier to get the balance of * @return Balance held by contracts using this library */ function getOwnBalance(address assetId) internal view returns (uint256) { return isNativeAsset(assetId) ? address(this).balance : IERC20(assetId).balanceOf(address(this)); } /** * @notice Transfers ether from the inheriting contract to a given * recipient * @param recipient Address to send ether to * @param amount Amount to send to given recipient */ function transferNativeAsset(address payable recipient, uint256 amount) internal { // solhint-disable-next-line avoid-low-level-calls (bool success, ) = recipient.call{ value: amount }(""); require(success, "#TNA:028"); } /** * @notice Gives approval for another address to spend tokens * @param assetId Token address to transfer * @param spender Address to give spend approval to * @param amount Amount to approve for spending */ function approveERC20( IERC20 assetId, address spender, uint256 amount ) internal { if (isNativeAsset(address(assetId))) return; uint256 allowance = assetId.allowance(address(this), spender); if (allowance > 0) SafeERC20.safeApprove(IERC20(assetId), spender, 0); SafeERC20.safeIncreaseAllowance(IERC20(assetId), spender, amount); } /** * @notice Transfers tokens from the inheriting contract to a given * recipient * @param assetId Token address to transfer * @param recipient Address to send ether to * @param amount Amount to send to given recipient */ function transferERC20( address assetId, address recipient, uint256 amount ) internal { SafeERC20.safeTransfer(IERC20(assetId), recipient, amount); } /** * @notice Transfers tokens from a sender to a given recipient * @param assetId Token address to transfer * @param from Address of sender/owner * @param to Address of recipient/spender * @param amount Amount to transfer from owner to spender */ function transferFromERC20( address assetId, address from, address to, uint256 amount ) internal { SafeERC20.safeTransferFrom(IERC20(assetId), from, to, amount); } /** * @notice Increases the allowance of a token to a spender * @param assetId Token address of asset to increase allowance of * @param spender Account whos allowance is increased * @param amount Amount to increase allowance by */ function increaseERC20Allowance( address assetId, address spender, uint256 amount ) internal { require(!isNativeAsset(assetId), "#IA:034"); SafeERC20.safeIncreaseAllowance(IERC20(assetId), spender, amount); } /** * @notice Decreases the allowance of a token to a spender * @param assetId Token address of asset to decrease allowance of * @param spender Account whos allowance is decreased * @param amount Amount to decrease allowance by */ function decreaseERC20Allowance( address assetId, address spender, uint256 amount ) internal { require(!isNativeAsset(assetId), "#DA:034"); SafeERC20.safeDecreaseAllowance(IERC20(assetId), spender, amount); } /** * @notice Wrapper function to transfer a given asset (native or erc20) to * some recipient. Should handle all non-compliant return value * tokens as well by using the SafeERC20 contract by open zeppelin. * @param assetId Asset id for transfer (address(0) for native asset, * token address for erc20s) * @param recipient Address to send asset to * @param amount Amount to send to given recipient */ function transferAsset( address assetId, address payable recipient, uint256 amount ) internal { isNativeAsset(assetId) ? transferNativeAsset(recipient, amount) : transferERC20(assetId, recipient, amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { LibAsset } from "./LibAsset.sol"; import { LibUtil } from "./LibUtil.sol"; library LibSwap { struct SwapData { address callTo; address approveTo; address sendingAssetId; address receivingAssetId; uint256 fromAmount; bytes callData; } event AssetSwapped( bytes32 transactionId, address dex, address fromAssetId, address toAssetId, uint256 fromAmount, uint256 toAmount, uint256 timestamp ); function swap(bytes32 transactionId, SwapData calldata _swapData) internal { uint256 fromAmount = _swapData.fromAmount; uint256 toAmount = LibAsset.getOwnBalance(_swapData.receivingAssetId); address fromAssetId = _swapData.sendingAssetId; if (!LibAsset.isNativeAsset(fromAssetId) && LibAsset.getOwnBalance(fromAssetId) < fromAmount) { LibAsset.transferFromERC20(_swapData.sendingAssetId, msg.sender, address(this), fromAmount); } if (!LibAsset.isNativeAsset(fromAssetId)) { LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount); } // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory res) = _swapData.callTo.call{ value: msg.value }(_swapData.callData); if (!success) { string memory reason = LibUtil.getRevertMsg(res); revert(reason); } toAmount = LibAsset.getOwnBalance(_swapData.receivingAssetId) - toAmount; emit AssetSwapped( transactionId, _swapData.callTo, _swapData.sendingAssetId, _swapData.receivingAssetId, fromAmount, toAmount, block.timestamp ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; interface IAnyswapToken { function underlying() external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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 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: MIT pragma solidity ^0.8.7; interface IDiamondCut { enum FacetCutAction { Add, Replace, Remove } // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } 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)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } 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"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @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"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "./LibBytes.sol"; library LibUtil { using LibBytes for bytes; function getRevertMsg(bytes memory _res) internal pure returns (string memory) { // If the _res length is less than 68, then the transaction failed silently (without a revert message) if (_res.length < 68) return "Transaction reverted silently"; bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes return abi.decode(revertData, (string)); // All that remains is the revert string } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; library LibBytes { // solhint-disable no-inline-assembly function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) // solhint-disable-next-line no-empty-blocks 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 pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { ITransactionManager } from "../Interfaces/ITransactionManager.sol"; import { ILiFi } from "../Interfaces/ILiFi.sol"; import { LibAsset } from "../Libraries/LibAsset.sol"; import { LibSwap } from "../Libraries/LibSwap.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; contract NXTPFacet is ILiFi { /* ========== Storage ========== */ bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.nxtp"); struct Storage { ITransactionManager nxtpTxManager; } /* ========== Events ========== */ event NXTPBridgeStarted( bytes32 indexed lifiTransactionId, bytes32 nxtpTransactionId, ITransactionManager.TransactionData txData ); /* ========== Init ========== */ function initNXTP(ITransactionManager _txMgrAddr) external { Storage storage s = getStorage(); LibDiamond.enforceIsContractOwner(); s.nxtpTxManager = _txMgrAddr; } /* ========== Public Bridge Functions ========== */ /** * @notice This function starts a cross-chain transaction using the NXTP protocol * @param _lifiData data used purely for tracking and analytics * @param _nxtpData data needed to complete an NXTP cross-chain transaction */ function startBridgeTokensViaNXTP(LiFiData memory _lifiData, ITransactionManager.PrepareArgs memory _nxtpData) public payable { // Ensure sender has enough to complete the bridge transaction address sendingAssetId = _nxtpData.invariantData.sendingAssetId; if (sendingAssetId == address(0)) require(msg.value == _nxtpData.amount, "ERR_INVALID_AMOUNT"); else { uint256 _sendingAssetIdBalance = LibAsset.getOwnBalance(sendingAssetId); LibAsset.transferFromERC20(sendingAssetId, msg.sender, address(this), _nxtpData.amount); require( LibAsset.getOwnBalance(sendingAssetId) - _sendingAssetIdBalance == _nxtpData.amount, "ERR_INVALID_AMOUNT" ); } // Start the bridge process _startBridge(_lifiData.transactionId, _nxtpData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /** * @notice This function performs a swap or multiple swaps and then starts a cross-chain transaction * using the NXTP protocol. * @param _lifiData data used purely for tracking and analytics * @param _swapData array of data needed for swaps * @param _nxtpData data needed to complete an NXTP cross-chain transaction */ function swapAndStartBridgeTokensViaNXTP( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, ITransactionManager.PrepareArgs memory _nxtpData ) public payable { address sendingAssetId = _nxtpData.invariantData.sendingAssetId; uint256 _sendingAssetIdBalance = LibAsset.getOwnBalance(sendingAssetId); // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } uint256 _postSwapBalance = LibAsset.getOwnBalance(sendingAssetId) - _sendingAssetIdBalance; require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT"); _nxtpData.amount = _postSwapBalance; _startBridge(_lifiData.transactionId, _nxtpData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /** * @notice Completes a cross-chain transaction on the receiving chain using the NXTP protocol. * @param _lifiData data used purely for tracking and analytics * @param assetId token received on the receiving chain * @param receiver address that will receive the tokens * @param amount number of tokens received */ function completeBridgeTokensViaNXTP( LiFiData memory _lifiData, address assetId, address receiver, uint256 amount ) public payable { if (LibAsset.isNativeAsset(assetId)) { require(msg.value == amount, "INVALID_ETH_AMOUNT"); } else { require(msg.value == 0, "ETH_WITH_ERC"); LibAsset.transferFromERC20(assetId, msg.sender, address(this), amount); } LibAsset.transferAsset(assetId, payable(receiver), amount); emit LiFiTransferCompleted(_lifiData.transactionId, assetId, receiver, amount, block.timestamp); } /** * @notice Performs a swap before completing a cross-chain transaction * on the receiving chain using the NXTP protocol. * @param _lifiData data used purely for tracking and analytics * @param _swapData array of data needed for swaps * @param finalAssetId token received on the receiving chain * @param receiver address that will receive the tokens */ function swapAndCompleteBridgeTokensViaNXTP( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, address finalAssetId, address receiver ) public payable { uint256 startingBalance = LibAsset.getOwnBalance(finalAssetId); // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } uint256 postSwapBalance = LibAsset.getOwnBalance(finalAssetId); uint256 finalBalance; if (postSwapBalance > startingBalance) { finalBalance = postSwapBalance - startingBalance; LibAsset.transferAsset(finalAssetId, payable(receiver), finalBalance); } emit LiFiTransferCompleted(_lifiData.transactionId, finalAssetId, receiver, finalBalance, block.timestamp); } /* ========== Internal Functions ========== */ function _startBridge(bytes32 _transactionId, ITransactionManager.PrepareArgs memory _nxtpData) internal { Storage storage s = getStorage(); IERC20 sendingAssetId = IERC20(_nxtpData.invariantData.sendingAssetId); // Give Connext approval to bridge tokens LibAsset.approveERC20(IERC20(sendingAssetId), address(s.nxtpTxManager), _nxtpData.amount); uint256 value = LibAsset.isNativeAsset(address(sendingAssetId)) ? msg.value : 0; // Initiate bridge transaction on sending chain ITransactionManager.TransactionData memory result = s.nxtpTxManager.prepare{ value: value }(_nxtpData); emit NXTPBridgeStarted(_transactionId, result.transactionId, result); } function getStorage() internal pure returns (Storage storage s) { bytes32 namespace = NAMESPACE; // solhint-disable-next-line no-inline-assembly assembly { s.slot := namespace } } /* ========== Getter Functions ========== */ /** * @notice show the NXTP transaction manager contract address */ function getNXTPTransactionManager() external view returns (address) { Storage storage s = getStorage(); return address(s.nxtpTxManager); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.7; interface ITransactionManager { // Structs // Holds all data that is constant between sending and // receiving chains. The hash of this is what gets signed // to ensure the signature can be used on both chains. struct InvariantTransactionData { address receivingChainTxManagerAddress; address user; address router; address initiator; // msg.sender of sending side address sendingAssetId; address receivingAssetId; address sendingChainFallback; // funds sent here on cancel address receivingAddress; address callTo; uint256 sendingChainId; uint256 receivingChainId; bytes32 callDataHash; // hashed to prevent free option bytes32 transactionId; } // Holds all data that varies between sending and receiving // chains. The hash of this is stored onchain to ensure the // information passed in is valid. struct VariantTransactionData { uint256 amount; uint256 expiry; uint256 preparedBlockNumber; } // All Transaction data, constant and variable struct TransactionData { address receivingChainTxManagerAddress; address user; address router; address initiator; // msg.sender of sending side address sendingAssetId; address receivingAssetId; address sendingChainFallback; address receivingAddress; address callTo; bytes32 callDataHash; bytes32 transactionId; uint256 sendingChainId; uint256 receivingChainId; uint256 amount; uint256 expiry; uint256 preparedBlockNumber; // Needed for removal of active blocks on fulfill/cancel } // The structure of the signed data for fulfill struct SignedFulfillData { bytes32 transactionId; uint256 relayerFee; string functionIdentifier; // "fulfill" or "cancel" uint256 receivingChainId; // For domain separation address receivingChainTxManagerAddress; // For domain separation } // The structure of the signed data for cancellation struct SignedCancelData { bytes32 transactionId; string functionIdentifier; uint256 receivingChainId; address receivingChainTxManagerAddress; // For domain separation } /** * Arguments for calling prepare() * @param invariantData The data for a crosschain transaction that will * not change between sending and receiving chains. * The hash of this data is used as the key to store * the inforamtion that does change between chains * (amount,expiry,preparedBlock) for verification * @param amount The amount of the transaction on this chain * @param expiry The block.timestamp when the transaction will no longer be * fulfillable and is freely cancellable on this chain * @param encryptedCallData The calldata to be executed when the tx is * fulfilled. Used in the function to allow the user * to reconstruct the tx from events. Hash is stored * onchain to prevent shenanigans. * @param encodedBid The encoded bid that was accepted by the user for this * crosschain transfer. It is supplied as a param to the * function but is only used in event emission * @param bidSignature The signature of the bidder on the encoded bid for * this transaction. Only used within the function for * event emission. The validity of the bid and * bidSignature are enforced offchain * @param encodedMeta The meta for the function */ struct PrepareArgs { InvariantTransactionData invariantData; uint256 amount; uint256 expiry; bytes encryptedCallData; bytes encodedBid; bytes bidSignature; bytes encodedMeta; } /** * @param txData All of the data (invariant and variant) for a crosschain * transaction. The variant data provided is checked against * what was stored when the `prepare` function was called. * @param relayerFee The fee that should go to the relayer when they are * calling the function on the receiving chain for the user * @param signature The users signature on the transaction id + fee that * can be used by the router to unlock the transaction on * the sending chain * @param callData The calldata to be sent to and executed by the * `FulfillHelper` * @param encodedMeta The meta for the function */ struct FulfillArgs { TransactionData txData; uint256 relayerFee; bytes signature; bytes callData; bytes encodedMeta; } /** * Arguments for calling cancel() * @param txData All of the data (invariant and variant) for a crosschain * transaction. The variant data provided is checked against * what was stored when the `prepare` function was called. * @param signature The user's signature that allows a transaction to be * cancelled by a relayer * @param encodedMeta The meta for the function */ struct CancelArgs { TransactionData txData; bytes signature; bytes encodedMeta; } // Adding/removing asset events event RouterAdded(address indexed addedRouter, address indexed caller); event RouterRemoved(address indexed removedRouter, address indexed caller); // Adding/removing router events event AssetAdded(address indexed addedAssetId, address indexed caller); event AssetRemoved(address indexed removedAssetId, address indexed caller); // Liquidity events event LiquidityAdded(address indexed router, address indexed assetId, uint256 amount, address caller); event LiquidityRemoved(address indexed router, address indexed assetId, uint256 amount, address recipient); // Transaction events event TransactionPrepared( address indexed user, address indexed router, bytes32 indexed transactionId, TransactionData txData, address caller, PrepareArgs args ); event TransactionFulfilled( address indexed user, address indexed router, bytes32 indexed transactionId, FulfillArgs args, bool success, bool isContract, bytes returnData, address caller ); event TransactionCancelled( address indexed user, address indexed router, bytes32 indexed transactionId, CancelArgs args, address caller ); // Getters function getChainId() external view returns (uint256); function getStoredChainId() external view returns (uint256); // Owner only methods function addRouter(address router) external; function removeRouter(address router) external; function addAssetId(address assetId) external; function removeAssetId(address assetId) external; // Router only methods function addLiquidityFor( uint256 amount, address assetId, address router ) external payable; function addLiquidity(uint256 amount, address assetId) external payable; function removeLiquidity( uint256 amount, address assetId, address payable recipient ) external; // Methods for crosschain transfers // called in the following order (in happy case) // 1. prepare by user on sending chain // 2. prepare by router on receiving chain // 3. fulfill by user on receiving chain // 4. fulfill by router on sending chain function prepare(PrepareArgs calldata args) external payable returns (TransactionData memory); function fulfill(FulfillArgs calldata args) external returns (TransactionData memory); function cancel(CancelArgs calldata args) external returns (TransactionData memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { LibDiamond } from "./Libraries/LibDiamond.sol"; import { IDiamondCut } from "./Interfaces/IDiamondCut.sol"; contract LiFiDiamond { constructor(address _contractOwner, address _diamondCutFacet) payable { LibDiamond.setContractOwner(_contractOwner); // Add the diamondCut external function from the diamondCutFacet IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1); bytes4[] memory functionSelectors = new bytes4[](1); functionSelectors[0] = IDiamondCut.diamondCut.selector; cut[0] = IDiamondCut.FacetCut({ facetAddress: _diamondCutFacet, action: IDiamondCut.FacetCutAction.Add, functionSelectors: functionSelectors }); LibDiamond.diamondCut(cut, address(0), ""); } // Find facet for function that is called and execute the // function if a facet is found and return any value. // solhint-disable-next-line no-complex-fallback fallback() external payable { LibDiamond.DiamondStorage storage ds; bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; // get diamond storage // solhint-disable-next-line no-inline-assembly assembly { ds.slot := position } // get facet from function selector address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress; require(facet != address(0), "Diamond: Function does not exist"); // Execute external function from facet using delegatecall and return any value. // solhint-disable-next-line no-inline-assembly assembly { // copy function selector and any arguments calldatacopy(0, 0, calldatasize()) // execute function call using the facet let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) // get any return value returndatacopy(0, 0, returndatasize()) // return any return value or error back to the caller switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } // Able to receive ether // solhint-disable-next-line no-empty-blocks receive() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { IDiamondCut } from "../Interfaces/IDiamondCut.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; contract DiamondCutFacet is IDiamondCut { /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external override { LibDiamond.enforceIsContractOwner(); LibDiamond.diamondCut(_diamondCut, _init, _calldata); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; contract WithdrawFacet { using SafeERC20 for IERC20; address private constant NATIVE_ASSET = address(0); event LogWithdraw(address indexed _assetAddress, address _from, uint256 amount); /** * @dev Withdraw asset. * @param _assetAddress Asset to be withdrawn. * @param _to address to withdraw to. * @param _amount amount of asset to withdraw. */ function withdraw( address _assetAddress, address _to, uint256 _amount ) public { LibDiamond.enforceIsContractOwner(); address sendTo = (_to == address(0)) ? msg.sender : _to; uint256 assetBalance; if (_assetAddress == NATIVE_ASSET) { address self = address(this); // workaround for a possible solidity bug assert(_amount <= self.balance); payable(sendTo).transfer(_amount); } else { assetBalance = IERC20(_assetAddress).balanceOf(address(this)); assert(_amount <= assetBalance); IERC20(_assetAddress).safeTransfer(sendTo, _amount); } emit LogWithdraw(sendTo, _assetAddress, _amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { ILiFi } from "../Interfaces/ILiFi.sol"; import { IHopBridge } from "../Interfaces/IHopBridge.sol"; import { LibAsset } from "../Libraries/LibAsset.sol"; import { LibSwap } from "../Libraries/LibSwap.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; contract HopFacet is ILiFi { /* ========== Storage ========== */ bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.hop"); struct Storage { mapping(string => IHopBridge.BridgeConfig) hopBridges; uint256 hopChainId; } /* ========== Types ========== */ struct HopData { string asset; address recipient; uint256 chainId; uint256 amount; uint256 bonderFee; uint256 amountOutMin; uint256 deadline; uint256 destinationAmountOutMin; uint256 destinationDeadline; } /* ========== Init ========== */ function initHop( string[] memory _tokens, IHopBridge.BridgeConfig[] memory _bridgeConfigs, uint256 _chainId ) external { Storage storage s = getStorage(); LibDiamond.enforceIsContractOwner(); for (uint8 i; i < _tokens.length; i++) { s.hopBridges[_tokens[i]] = _bridgeConfigs[i]; } s.hopChainId = _chainId; } /* ========== Public Bridge Functions ========== */ /** * @notice Bridges tokens via Hop Protocol * @param _lifiData data used purely for tracking and analytics * @param _hopData data specific to Hop Protocol */ function startBridgeTokensViaHop(LiFiData memory _lifiData, HopData calldata _hopData) public payable { address fromToken = _bridge(_hopData.asset).token; uint256 _fromTokenBalance = LibAsset.getOwnBalance(fromToken); LibAsset.transferFromERC20(fromToken, msg.sender, address(this), _hopData.amount); require(LibAsset.getOwnBalance(fromToken) - _fromTokenBalance == _hopData.amount, "ERR_INVALID_AMOUNT"); _startBridge(_hopData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /** * @notice Performs a swap before bridging via Hop Protocol * @param _lifiData data used purely for tracking and analytics * @param _swapData an array of swap related data for performing swaps before bridging * @param _hopData data specific to Hop Protocol */ function swapAndStartBridgeTokensViaHop( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, HopData calldata _hopData ) public payable { address fromToken = _bridge(_hopData.asset).token; uint256 _fromTokenBalance = LibAsset.getOwnBalance(fromToken); // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } require(LibAsset.getOwnBalance(fromToken) - _fromTokenBalance >= _hopData.amount, "ERR_INVALID_AMOUNT"); _startBridge(_hopData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /* ========== Internal Functions ========== */ /** * @dev Conatains the business logic for the bridge via Hop Protocol * @param _hopData data specific to Hop Protocol */ function _startBridge(HopData calldata _hopData) internal { Storage storage s = getStorage(); address fromToken = _bridge(_hopData.asset).token; address bridge; if (s.hopChainId == 1) { bridge = _bridge(_hopData.asset).bridge; } else { bridge = _bridge(_hopData.asset).ammWrapper; } // Do HOP stuff require(s.hopChainId != _hopData.chainId, "Cannot bridge to the same network."); // Give Hop approval to bridge tokens LibAsset.approveERC20(IERC20(fromToken), bridge, _hopData.amount); if (s.hopChainId == 1) { // Ethereum L1 IHopBridge(bridge).sendToL2( _hopData.chainId, _hopData.recipient, _hopData.amount, _hopData.destinationAmountOutMin, _hopData.destinationDeadline, address(0), 0 ); } else { // L2 // solhint-disable-next-line check-send-result IHopBridge(bridge).swapAndSend( _hopData.chainId, _hopData.recipient, _hopData.amount, _hopData.bonderFee, _hopData.amountOutMin, _hopData.deadline, _hopData.destinationAmountOutMin, _hopData.destinationDeadline ); } } function _bridge(string memory _asset) internal view returns (IHopBridge.BridgeConfig memory) { Storage storage s = getStorage(); return s.hopBridges[_asset]; } function getStorage() internal pure returns (Storage storage s) { bytes32 namespace = NAMESPACE; // solhint-disable-next-line no-inline-assembly assembly { s.slot := namespace } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; interface IHopBridge { struct BridgeConfig { address token; address bridge; address ammWrapper; } function sendToL2( uint256 chainId, address recipient, uint256 amount, uint256 amountOutMin, uint256 deadline, address relayer, uint256 relayerFee ) external payable; function swapAndSend( uint256 chainId, address recipient, uint256 amount, uint256 bonderFee, uint256 amountOutMin, uint256 deadline, uint256 destinationAmountOutMin, uint256 destinationDeadline ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { ILiFi } from "../Interfaces/ILiFi.sol"; import { LibAsset } from "../Libraries/LibAsset.sol"; import { LibSwap } from "../Libraries/LibSwap.sol"; import { LibUtil } from "../Libraries/LibUtil.sol"; contract GenericBridgeFacet is ILiFi { /* ========== Types ========== */ struct BridgeData { uint256 amount; address assetId; address callTo; bytes callData; } /* ========== Public Bridge Functions ========== */ /** * @notice Bridges tokens via Generic Bridge * @param _lifiData data used purely for tracking and analytics * @param _bridgeData data used for bridging via various contracts */ function startBridgeTokensGeneric(LiFiData memory _lifiData, BridgeData memory _bridgeData) public payable { LibAsset.transferFromERC20(_bridgeData.assetId, msg.sender, address(this), _bridgeData.amount); _startBridge(_bridgeData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /** * @notice Performs a swap before bridging via Hop Protocol * @param _lifiData data used purely for tracking and analytics * @param _swapData an array of swap related data for performing swaps before bridging * @param _bridgeData data used for bridging via various contracts */ function swapAndStartBridgeTokensGeneric( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, BridgeData memory _bridgeData ) public payable { uint256 _fromTokenBalance = LibAsset.getOwnBalance(_bridgeData.assetId); // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } require( LibAsset.getOwnBalance(_bridgeData.assetId) - _fromTokenBalance >= _bridgeData.amount, "ERR_INVALID_AMOUNT" ); _startBridge(_bridgeData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /* ========== Internal Functions ========== */ /** * @dev Conatains the business logic for the bridge via Hop Protocol */ function _startBridge(BridgeData memory _bridgeData) internal { LibAsset.approveERC20(IERC20(_bridgeData.assetId), _bridgeData.callTo, _bridgeData.amount); (bool success, bytes memory res) = _bridgeData.callTo.call{ value: msg.value }(_bridgeData.callData); if (!success) { string memory reason = LibUtil.getRevertMsg(res); revert(reason); } } }
// SPDX-License-Identifier: MIT // for testing only not for production // solhint-disable pragma solidity ^0.8.3; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract USDT is ERC20 { constructor( address receiver, string memory name, string memory symbol ) ERC20(name, symbol) { // Mint 100 tokens to msg.sender // Similar to how // 1 dollar = 100 cents // 1 token = 1 * (10 ** decimals) _mint(receiver, 10000 * 10**uint256(6)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { LibAsset } from "../Libraries/LibAsset.sol"; import { ILiFi } from "../Interfaces/ILiFi.sol"; import { LibSwap } from "../Libraries/LibSwap.sol"; import { ICBridge } from "../Interfaces/ICBridge.sol"; import { LibDiamond } from "../Libraries/LibDiamond.sol"; contract CBridgeFacet is ILiFi { /* ========== Storage ========== */ bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.cbridge"); struct Storage { address cBridge; uint256 cBridgeChainId; } /* ========== Types ========== */ struct CBridgeData { address bridge; address token; uint256 amount; bytes32 hashlock; uint64 timelock; uint64 dstChainId; address dstAddress; } /* ========== Init ========== */ function initCbridge(address _cBridge, uint256 _chainId) external { Storage storage s = getStorage(); LibDiamond.enforceIsContractOwner(); s.cBridge = _cBridge; s.cBridgeChainId = _chainId; } /* ========== Public Bridge Functions ========== */ function startBridgeTokensViaCBridge(LiFiData memory _lifiData, CBridgeData calldata _cBridgeData) public payable { uint256 _fromTokenBalance = LibAsset.getOwnBalance(_cBridgeData.token); LibAsset.transferFromERC20(_cBridgeData.token, msg.sender, address(this), _cBridgeData.amount); require( LibAsset.getOwnBalance(_cBridgeData.token) - _fromTokenBalance == _cBridgeData.amount, "ERR_INVALID_AMOUNT" ); _startBridge(_cBridgeData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } function swapAndStartBridgeTokensViaCBridge( LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData, CBridgeData calldata _cBridgeData ) public payable { uint256 _fromTokenBalance = LibAsset.getOwnBalance(_cBridgeData.token); LibAsset.transferFromERC20(_cBridgeData.token, msg.sender, address(this), _cBridgeData.amount); // Swap for (uint8 i; i < _swapData.length; i++) { LibSwap.swap(_lifiData.transactionId, _swapData[i]); } require( LibAsset.getOwnBalance(_cBridgeData.token) - _fromTokenBalance == _cBridgeData.amount, "ERR_INVALID_AMOUNT" ); _startBridge(_cBridgeData); emit LiFiTransferStarted( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } /* ========== Internal Functions ========== */ /* * @dev Conatains the business logic for the bridge via CBridge * @param _cBridgeData data specific to CBridge */ function _startBridge(CBridgeData calldata _cBridgeData) internal { Storage storage s = getStorage(); address bridge = _bridge(); // Do CBridge stuff require(s.cBridgeChainId != _cBridgeData.dstChainId, "Cannot bridge to the same network."); // Give CBridge approval to bridge tokens LibAsset.approveERC20(IERC20(_cBridgeData.token), bridge, _cBridgeData.amount); ICBridge(bridge).transferOut( _cBridgeData.bridge, _cBridgeData.token, _cBridgeData.amount, _cBridgeData.hashlock, _cBridgeData.timelock, _cBridgeData.dstChainId, _cBridgeData.dstAddress ); } function confirmTransaction( LiFiData memory _lifiData, bytes32 _transferId, bytes32 _preimage ) public { address bridge = _bridge(); ICBridge(bridge).confirm(_transferId, _preimage); emit LiFiTransferConfirmed( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } function refund(LiFiData memory _lifiData, bytes32 _transferId) public { address bridge = _bridge(); ICBridge(bridge).refund(_transferId); emit LiFiTransferRefunded( _lifiData.transactionId, _lifiData.integrator, _lifiData.referrer, _lifiData.sendingAssetId, _lifiData.receivingAssetId, _lifiData.receiver, _lifiData.amount, _lifiData.destinationChainId, block.timestamp ); } function _bridge() internal view returns (address) { Storage storage s = getStorage(); return s.cBridge; } function getStorage() internal pure returns (Storage storage s) { bytes32 namespace = NAMESPACE; // solhint-disable-next-line no-inline-assembly assembly { s.slot := namespace } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; interface ICBridge { struct BridgeConfig { address bridge; } function transferOut( address _bridge, address _token, uint256 _amount, bytes32 _hashlock, uint64 _timelock, uint64 _dstChinId, address _dstAddress ) external; function transferIn( address _dstAddress, address _token, uint256 _amount, bytes32 _hashlock, uint64 _timelock, uint64 _srcChainId, bytes32 _srcTransferId ) external; function confirm(bytes32 _transferId, bytes32 _preimage) external; function refund(bytes32 _transferId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { LibDiamond } from "../Libraries/LibDiamond.sol"; import { IERC173 } from "../Interfaces/IERC173.sol"; contract OwnershipFacet is IERC173 { function transferOwnership(address _newOwner) external override { LibDiamond.enforceIsContractOwner(); LibDiamond.setContractOwner(_newOwner); } function owner() external view override returns (address owner_) { owner_ = LibDiamond.contractOwner(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; /// @title ERC-173 Contract Ownership Standard /// Note: the ERC-165 identifier for this interface is 0x7f5828d0 /* is ERC165 */ interface IERC173 { /// @dev This emits when ownership of a contract changes. event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /// @notice Get the address of the owner /// @return owner_ The address of the owner. function owner() external view returns (address owner_); /// @notice Set the address of the new owner of the contract /// @dev Set _newOwner to address(0) to renounce any ownership. /// @param _newOwner The address of the new owner of the contract function transferOwnership(address _newOwner) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { LibDiamond } from "../Libraries/LibDiamond.sol"; import { IDiamondLoupe } from "../Interfaces/IDiamondLoupe.sol"; import { IERC165 } from "../Interfaces/IERC165.sol"; contract DiamondLoupeFacet is IDiamondLoupe, IERC165 { // Diamond Loupe Functions //////////////////////////////////////////////////////////////////// /// These functions are expected to be called frequently by tools. // // struct Facet { // address facetAddress; // bytes4[] functionSelectors; // } /// @notice Gets all facets and their selectors. /// @return facets_ Facet function facets() external view override returns (Facet[] memory facets_) { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); uint256 numFacets = ds.facetAddresses.length; facets_ = new Facet[](numFacets); for (uint256 i; i < numFacets; i++) { address facetAddress_ = ds.facetAddresses[i]; facets_[i].facetAddress = facetAddress_; facets_[i].functionSelectors = ds.facetFunctionSelectors[facetAddress_].functionSelectors; } } /// @notice Gets all the function selectors provided by a facet. /// @param _facet The facet address. /// @return facetFunctionSelectors_ function facetFunctionSelectors(address _facet) external view override returns (bytes4[] memory facetFunctionSelectors_) { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); facetFunctionSelectors_ = ds.facetFunctionSelectors[_facet].functionSelectors; } /// @notice Get all the facet addresses used by a diamond. /// @return facetAddresses_ function facetAddresses() external view override returns (address[] memory facetAddresses_) { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); facetAddresses_ = ds.facetAddresses; } /// @notice Gets the facet that supports the given selector. /// @dev If facet is not found return address(0). /// @param _functionSelector The function selector. /// @return facetAddress_ The facet address. function facetAddress(bytes4 _functionSelector) external view override returns (address facetAddress_) { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); facetAddress_ = ds.selectorToFacetAndPosition[_functionSelector].facetAddress; } // This implements ERC-165. function supportsInterface(bytes4 _interfaceId) external view override returns (bool) { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); return ds.supportedInterfaces[_interfaceId]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; // A loupe is a small magnifying glass used to look at diamonds. // These functions look at diamonds interface IDiamondLoupe { /// These functions are expected to be called frequently /// by tools. struct Facet { address facetAddress; bytes4[] functionSelectors; } /// @notice Gets all facet addresses and their four byte function selectors. /// @return facets_ Facet function facets() external view returns (Facet[] memory facets_); /// @notice Gets all the function selectors supported by a specific facet. /// @param _facet The facet address. /// @return facetFunctionSelectors_ function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_); /// @notice Get all the facet addresses used by a diamond. /// @return facetAddresses_ function facetAddresses() external view returns (address[] memory facetAddresses_); /// @notice Gets the facet that supports the given selector. /// @dev If facet is not found return address(0). /// @param _functionSelector The function selector. /// @return facetAddress_ The facet address. function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; interface IERC165 { /// @notice Query if a contract implements an interface /// @param interfaceId The interface identifier, as specified in ERC-165 /// @dev Interface identification is specified in ERC-165. This function /// uses less than 30,000 gas. /// @return `true` if the contract implements `interfaceID` and /// `interfaceID` is not 0xffffffff, `false` otherwise function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamondCut.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"indexed":false,"internalType":"struct IDiamondCut.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"_init","type":"address"},{"indexed":false,"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"DiamondCut","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamondCut.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"internalType":"struct IDiamondCut.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"internalType":"address","name":"_init","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"diamondCut","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506114b2806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80631f931c1c14610030575b600080fd5b61004361003e366004610eac565b610045565b005b61004d61009e565b61009761005a85876111ec565b8484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061011a92505050565b5050505050565b600080516020611411833981519152600401546001600160a01b031633146101185760405162461bcd60e51b815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201526132b960f11b60648201526084015b60405180910390fd5b565b60005b83518110156102e357600084828151811061013a5761013a6113e4565b60200260200101516020015190506000600281111561015b5761015b6113b8565b81600281111561016d5761016d6113b8565b14156101bc576101b7858381518110610188576101886113e4565b6020026020010151600001518684815181106101a6576101a66113e4565b60200260200101516040015161032e565b6102d0565b60018160028111156101d0576101d06113b8565b141561021a576101b78583815181106101eb576101eb6113e4565b602002602001015160000151868481518110610209576102096113e4565b6020026020010151604001516104a3565b600281600281111561022e5761022e6113b8565b1415610278576101b7858381518110610249576102496113e4565b602002602001015160000151868481518110610267576102676113e4565b602002602001015160400151610631565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b606482015260840161010f565b50806102db81611360565b91505061011d565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67383838360405161031793929190610fa6565b60405180910390a1610329828261074f565b505050565b600081511161034f5760405162461bcd60e51b815260040161010f906110c0565b6000805160206114118339815191526001600160a01b0383166103845760405162461bcd60e51b815260040161010f9061110b565b6001600160a01b03831660009081526001820160205260409020546001600160601b0381166103b7576103b7828561095c565b60005b83518110156100975760008482815181106103d7576103d76113e4565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b031680156104755760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f6044820152746e207468617420616c72656164792065786973747360581b606482015260840161010f565b6104818583868a6109c6565b8361048b8161137b565b9450505050808061049b90611360565b9150506103ba565b60008151116104c45760405162461bcd60e51b815260040161010f906110c0565b6000805160206114118339815191526001600160a01b0383166104f95760405162461bcd60e51b815260040161010f9061110b565b6001600160a01b03831660009081526001820160205260409020546001600160601b03811661052c5761052c828561095c565b60005b835181101561009757600084828151811061054c5761054c6113e4565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b039081169087168114156105f85760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e0000000000000000606482015260840161010f565b610603858284610a66565b61060f8583868a6109c6565b836106198161137b565b9450505050808061062990611360565b91505061052f565b60008151116106525760405162461bcd60e51b815260040161010f906110c0565b6000805160206114118339815191526001600160a01b038316156106d75760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f76652066616365742061646472604482015275657373206d757374206265206164647265737328302960501b606482015260840161010f565b60005b82518110156107495760008382815181106106f7576106f76113e4565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b0316610734848284610a66565b5050808061074190611360565b9150506106da565b50505050565b6001600160a01b0382166107d6578051156107d25760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d70747900000000606482015260840161010f565b5050565b600081511161084d5760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f742061646472657373283029000000606482015260840161010f565b6001600160a01b038216301461087f5761087f8260405180606001604052806028815260200161143160289139610e26565b600080836001600160a01b03168360405161089a9190610f8a565b600060405180830381855af49150503d80600081146108d5576040519150601f19603f3d011682016040523d82523d6000602084013e6108da565b606091505b50915091508161074957805115610905578060405162461bcd60e51b815260040161010f91906110a6565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b606482015260840161010f565b61097e8160405180606001604052806024815260200161145960249139610e26565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160e01b0319831660008181526020868152604080832080546001600160601b03909716600160a01b026001600160a01b0397881617815594909516808352600180890183529583208054968701815583528183206008870401805460e09890981c60046007909816979097026101000a96870263ffffffff9097021990971695909517909555529290915281546001600160a01b031916179055565b6001600160a01b038216610ae25760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e2774206578697374000000000000000000606482015260840161010f565b6001600160a01b038216301415610b525760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b606482015260840161010f565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b03169291610ba1916111d5565b9050808214610c93576001600160a01b03841660009081526001860160205260408120805483908110610bd657610bd66113e4565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110610c2757610c276113e4565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b03841660009081526001860160205260409020805480610cbc57610cbc6113ce565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b031985168252869052604081205580610097576002850154600090610d1b906001906111d5565b6001600160a01b0386166000908152600180890160205260409091200154909150808214610dca576000876002018381548110610d5a57610d5a6113e4565b6000918252602090912001546002890180546001600160a01b039092169250829184908110610d8b57610d8b6113e4565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480610ddd57610ddd6113ce565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b81816107495760405162461bcd60e51b815260040161010f91906110a6565b80356001600160a01b0381168114610e5e57600080fd5b919050565b60008083601f840112610e7557600080fd5b50813567ffffffffffffffff811115610e8d57600080fd5b602083019150836020828501011115610ea557600080fd5b9250929050565b600080600080600060608688031215610ec457600080fd5b853567ffffffffffffffff80821115610edc57600080fd5b818801915088601f830112610ef057600080fd5b813581811115610eff57600080fd5b8960208260051b8501011115610f1457600080fd5b60208301975080965050610f2a60208901610e47565b94506040880135915080821115610f4057600080fd5b50610f4d88828901610e63565b969995985093965092949392505050565b60008151808452610f76816020860160208601611334565b601f01601f19169290920160200192915050565b60008251610f9c818460208701611334565b9190910192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101561107657898403607f19018652815180516001600160a01b0316855283810151898601906003811061101557634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156110615783516001600160e01b0319168252928601926001929092019190860190611037565b50978501979550505090820190600101610fcf565b50506001600160a01b038a169088015286810360408801526110988189610f5e565b9a9950505050505050505050565b6020815260006110b96020830184610f5e565b9392505050565b6020808252602b908201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201526a1858d95d081d1bc818dd5d60aa1b606082015260800190565b6020808252602c908201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201526b65206164647265737328302960a01b606082015260800190565b6040516060810167ffffffffffffffff8111828210171561117a5761117a6113fa565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156111a9576111a96113fa565b604052919050565b600067ffffffffffffffff8211156111cb576111cb6113fa565b5060051b60200190565b6000828210156111e7576111e76113a2565b500390565b60006111ff6111fa846111b1565b611180565b838152602080820191908460053688821b8301111561121d57600080fd5b60005b8881101561132757823567ffffffffffffffff8082111561124057600080fd5b818a0191506060823603121561125557600080fd5b61125d611157565b61126683610e47565b8152868301356003811061127957600080fd5b818801526040838101358381111561129057600080fd5b939093019236601f8501126112a457600080fd5b833592506112b46111fa846111b1565b83815288810190858a0136868a1b88018c0111156112d157600080fd5b600096505b8587101561130a5780356001600160e01b0319811681146112f657600080fd5b835260019690960195918a01918a016112d6565b509183019190915250885250509483019491830191600101611220565b5092979650505050505050565b60005b8381101561134f578181015183820152602001611337565b838111156107495750506000910152565b6000600019821415611374576113746113a2565b5060010190565b60006001600160601b0380831681811415611398576113986113a2565b6001019392505050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a2646970667358221220cb3608f985e15fe1c810d3b025db6fcab323b52b076c5ed6b949dd3015c7d6a564736f6c63430008070033
Deployed ByteCode Sourcemap
177:747:8:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;666:256;;;;;;:::i;:::-;;:::i;:::-;;;818:35;:33;:35::i;:::-;863:52;;885:11;;863:52;:::i;:::-;898:5;905:9;;863:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;863:21:8;;-1:-1:-1;;;863:52:8:i;:::-;666:256;;;;;:::o;2024:156:28:-;-1:-1:-1;;;;;;;;;;;2104:30:28;;;-1:-1:-1;;;;;2104:30:28;2090:10;:44;2082:91;;;;-1:-1:-1;;;2082:91:28;;5566:2:32;2082:91:28;;;5548:21:32;5605:2;5585:18;;;5578:30;5644:34;5624:18;;;5617:62;-1:-1:-1;;;5695:18:32;;;5688:32;5737:19;;2082:91:28;;;;;;;;;2024:156::o;2324:1067::-;2480:18;2475:806;2513:11;:18;2500:10;:31;2475:806;;;2561:33;2597:11;2609:10;2597:23;;;;;;;;:::i;:::-;;;;;;;:30;;;2561:66;;2655:30;2645:40;;;;;;;;:::i;:::-;:6;:40;;;;;;;;:::i;:::-;;2641:630;;;2705:93;2718:11;2730:10;2718:23;;;;;;;;:::i;:::-;;;;;;;:36;;;2756:11;2768:10;2756:23;;;;;;;;:::i;:::-;;;;;;;:41;;;2705:12;:93::i;:::-;2641:630;;;2833:34;2823:6;:44;;;;;;;;:::i;:::-;;2819:452;;;2887:97;2904:11;2916:10;2904:23;;;;;;;;:::i;:::-;;;;;;;:36;;;2942:11;2954:10;2942:23;;;;;;;;:::i;:::-;;;;;;;:41;;;2887:16;:97::i;2819:452::-;3019:33;3009:6;:43;;;;;;;;:::i;:::-;;3005:266;;;3072:96;3088:11;3100:10;3088:23;;;;;;;;:::i;:::-;;;;;;;:36;;;3126:11;3138:10;3126:23;;;;;;;;:::i;:::-;;;;;;;:41;;;3072:15;:96::i;3005:266::-;3207:49;;-1:-1:-1;;;3207:49:28;;6805:2:32;3207:49:28;;;6787:21:32;6844:2;6824:18;;;6817:30;6883:34;6863:18;;;6856:62;-1:-1:-1;;;6934:18:32;;;6927:37;6981:19;;3207:49:28;6603:403:32;3005:266:28;-1:-1:-1;2533:12:28;;;;:::i;:::-;;;;2475:806;;;;3295:41;3306:11;3319:5;3326:9;3295:41;;;;;;;;:::i;:::-;;;;;;;;3346:38;3367:5;3374:9;3346:20;:38::i;:::-;2324:1067;;;:::o;3397:1069::-;3533:1;3505:18;:25;:29;3497:85;;;;-1:-1:-1;;;3497:85:28;;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;3654:27:28;;3646:84;;;;-1:-1:-1;;;3646:84:28;;;;;;;:::i;:::-;-1:-1:-1;;;;;3773:40:28;;3740:23;3773:40;;;:25;;;:40;;;;;:65;-1:-1:-1;;;;;3907:21:28;;3903:79;;3944:27;3953:2;3957:13;3944:8;:27::i;:::-;3996:21;3991:469;4035:18;:25;4019:13;:41;3991:469;;;4093:15;4111:18;4130:13;4111:33;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;;4184:39:28;;4158:23;4184:39;;;;;;;;;;;:52;4111:33;;-1:-1:-1;;;;;;4184:52:28;4258:29;;4250:95;;;;-1:-1:-1;;;4250:95:28;;8471:2:32;4250:95:28;;;8453:21:32;8510:2;8490:18;;;8483:30;8549:34;8529:18;;;8522:62;-1:-1:-1;;;8600:18:32;;;8593:51;8661:19;;4250:95:28;8269:417:32;4250:95:28;4359:58;4371:2;4375:8;4385:16;4403:13;4359:11;:58::i;:::-;4431:18;;;;:::i;:::-;;;;4079:381;;4062:15;;;;;:::i;:::-;;;;3991:469;;4472:1138;4612:1;4584:18;:25;:29;4576:85;;;;-1:-1:-1;;;4576:85:28;;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;4733:27:28;;4725:84;;;;-1:-1:-1;;;4725:84:28;;;;;;;:::i;:::-;-1:-1:-1;;;;;4852:40:28;;4819:23;4852:40;;;:25;;;:40;;;;;:65;-1:-1:-1;;;;;4986:21:28;;4982:79;;5023:27;5032:2;5036:13;5023:8;:27::i;:::-;5075:21;5070:534;5114:18;:25;5098:13;:41;5070:534;;;5172:15;5190:18;5209:13;5190:33;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;;5263:39:28;;5237:23;5263:39;;;;;;;;;;;:52;5190:33;;-1:-1:-1;;;;;;5263:52:28;;;;5337:32;;;;;5329:101;;;;-1:-1:-1;;;5329:101:28;;8893:2:32;5329:101:28;;;8875:21:32;8932:2;8912:18;;;8905:30;8971:34;8951:18;;;8944:62;9042:26;9022:18;;;9015:54;9086:19;;5329:101:28;8691:420:32;5329:101:28;5444:45;5459:2;5463:15;5480:8;5444:14;:45::i;:::-;5503:58;5515:2;5519:8;5529:16;5547:13;5503:11;:58::i;:::-;5575:18;;;;:::i;:::-;;;;5158:446;;5141:15;;;;;:::i;:::-;;;;5070:534;;5616:742;5755:1;5727:18;:25;:29;5719:85;;;;-1:-1:-1;;;5719:85:28;;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;5941:27:28;;;5933:94;;;;-1:-1:-1;;;5933:94:28;;9318:2:32;5933:94:28;;;9300:21:32;9357:2;9337:18;;;9330:30;9396:34;9376:18;;;9369:62;-1:-1:-1;;;9447:18:32;;;9440:52;9509:19;;5933:94:28;9116:418:32;5933:94:28;6042:21;6037:315;6081:18;:25;6065:13;:41;6037:315;;;6139:15;6157:18;6176:13;6157:33;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;;6230:39:28;;6204:23;6230:39;;;;;;;;;;;:52;6157:33;;-1:-1:-1;;;;;;6230:52:28;6296:45;6230:2;:52;6157:33;6296:14;:45::i;:::-;6125:227;;6108:15;;;;;:::i;:::-;;;;6037:315;;;;5709:649;5616:742;;:::o;9337:934::-;-1:-1:-1;;;;;9429:19:28;;9425:840;;9472:16;;:21;9464:94;;;;-1:-1:-1;;;9464:94:28;;4730:2:32;9464:94:28;;;4712:21:32;4769:2;4749:18;;;4742:30;4808:34;4788:18;;;4781:62;4879:30;4859:18;;;4852:58;4927:19;;9464:94:28;4528:424:32;9464:94:28;9337:934;;:::o;9425:840::-;9616:1;9597:9;:16;:20;9589:94;;;;-1:-1:-1;;;9589:94:28;;7626:2:32;9589:94:28;;;7608:21:32;7665:2;7645:18;;;7638:30;7704:34;7684:18;;;7677:62;7775:31;7755:18;;;7748:59;7824:19;;9589:94:28;7424:425:32;9589:94:28;-1:-1:-1;;;;;9701:22:28;;9718:4;9701:22;9697:134;;9743:73;9766:5;9743:73;;;;;;;;;;;;;;;;;:22;:73::i;:::-;9908:12;9922:18;9944:5;-1:-1:-1;;;;;9944:18:28;9963:9;9944:29;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9907:66;;;;9992:7;9987:268;;10023:12;;:16;10019:222;;10120:5;10106:21;;-1:-1:-1;;;10106:21:28;;;;;;;;:::i;10019:222::-;10174:48;;-1:-1:-1;;;10174:48:28;;5159:2:32;10174:48:28;;;5141:21:32;5198:2;5178:18;;;5171:30;5237:34;5217:18;;;5210:62;-1:-1:-1;;;5288:18:32;;;5281:36;5334:19;;10174:48:28;4957:402:32;6364:316:28;6451:77;6474:13;6451:77;;;;;;;;;;;;;;;;;:22;:77::i;:::-;6602:17;;;:24;;-1:-1:-1;;;;;6538:40:28;;;;;;;:25;;;;:40;;;;;;;:61;;:88;;;6636:37;;;;;;;;;;;;;;-1:-1:-1;;;;;;6636:37:28;;;;;;6364:316::o;6686:427::-;-1:-1:-1;;;;;;6858:40:28;;:29;:40;;;;;;;;;;;:85;;-1:-1:-1;;;;;6858:85:28;;;-1:-1:-1;;;6858:85:28;-1:-1:-1;;;;;6858:85:28;;;;;;6953:40;;;;;;;-1:-1:-1;6953:25:28;;;:40;;;;;:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6858:85;6953:74;;;;;;;;;;;;;;;;;;;7037:40;;;;;:69;;-1:-1:-1;;;;;;7037:69:28;;;;6686:427::o;7119:2212::-;-1:-1:-1;;;;;7268:27:28;;7260:95;;;;-1:-1:-1;;;7260:95:28;;6381:2:32;7260:95:28;;;6363:21:32;6420:2;6400:18;;;6393:30;6459:34;6439:18;;;6432:62;6530:25;6510:18;;;6503:53;6573:19;;7260:95:28;6179:419:32;7260:95:28;-1:-1:-1;;;;;7450:30:28;;7475:4;7450:30;;7442:89;;;;-1:-1:-1;;;7442:89:28;;8056:2:32;7442:89:28;;;8038:21:32;8095:2;8075:18;;;8068:30;8134:34;8114:18;;;8107:62;-1:-1:-1;;;8185:18:32;;;8178:44;8239:19;;7442:89:28;7854:410:32;7442:89:28;-1:-1:-1;;;;;;7642:40:28;;7615:24;7642:40;;;;;;;;;;;:65;-1:-1:-1;;;;;7748:40:28;;;;7816:1;7748:25;;;:40;;;;;;:65;-1:-1:-1;;;7642:65:28;;;-1:-1:-1;;;;;7642:65:28;;7615:24;7748:69;;;:::i;:::-;7717:100;;7919:20;7899:16;:40;7895:387;;-1:-1:-1;;;;;7977:40:28;;7955:19;7977:40;;;:25;;;:40;;;;;:80;;8036:20;;7977:80;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;;;;;8071:40:28;;;;:25;;;:40;;;;;;;:76;;7977:80;;;;;;;;;;;;;;-1:-1:-1;7977:80:28;;8071:40;8130:16;;8071:76;;;;;;:::i;:::-;;;;;;;;;;;;;:91;;;:76;;;;;;:91;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;8176:43:28;;;;;;;;;;;;:95;;-1:-1:-1;;;;;8176:95:28;-1:-1:-1;;;;;;;;8176:95:28;;;;;;7895:387;-1:-1:-1;;;;;8327:40:28;;;;;;:25;;;:40;;;;;:64;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;8327:64:28;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;8408:40:28;;;;;;;;;;8401:47;8543:25;8539:786;;8710:17;;;:24;8675:32;;8710:28;;8737:1;;8710:28;:::i;:::-;-1:-1:-1;;;;;8783:40:28;;8752:28;8783:40;;;:25;;;;:40;;;;;;:61;;8675:63;;-1:-1:-1;8862:48:28;;;8858:338;;8930:24;8957:2;:17;;8975:24;8957:43;;;;;;;;:::i;:::-;;;;;;;;;;;9018:17;;;:39;;-1:-1:-1;;;;;8957:43:28;;;;-1:-1:-1;8957:43:28;;9036:20;;9018:39;;;;;;:::i;:::-;;;;;;;;;;;;;:58;;-1:-1:-1;;;;;;9018:58:28;-1:-1:-1;;;;;9018:58:28;;;;;;9094:43;;;;;;-1:-1:-1;9094:25:28;;;:43;;;;;;:64;:87;;;8858:338;9209:2;:17;;:23;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;9209:23:28;;;;;-1:-1:-1;;;;;;9209:23:28;;;;;;;;;-1:-1:-1;;;;;9253:40:28;;;;9209:23;9253:25;;;:40;;;;;;:61;9246:68;-1:-1:-1;;7250:2081:28;;7119:2212;;;:::o;10277:317::-;10506:22;;10573:13;10555:16;10547:40;;;;-1:-1:-1;;;10547:40:28;;;;;;;;:::i;14:173:32:-;82:20;;-1:-1:-1;;;;;131:31:32;;121:42;;111:70;;177:1;174;167:12;111:70;14:173;;;:::o;192:347::-;243:8;253:6;307:3;300:4;292:6;288:17;284:27;274:55;;325:1;322;315:12;274:55;-1:-1:-1;348:20:32;;391:18;380:30;;377:50;;;423:1;420;413:12;377:50;460:4;452:6;448:17;436:29;;512:3;505:4;496:6;488;484:19;480:30;477:39;474:59;;;529:1;526;519:12;474:59;192:347;;;;;:::o;544:1010::-;687:6;695;703;711;719;772:2;760:9;751:7;747:23;743:32;740:52;;;788:1;785;778:12;740:52;828:9;815:23;857:18;898:2;890:6;887:14;884:34;;;914:1;911;904:12;884:34;952:6;941:9;937:22;927:32;;997:7;990:4;986:2;982:13;978:27;968:55;;1019:1;1016;1009:12;968:55;1059:2;1046:16;1085:2;1077:6;1074:14;1071:34;;;1101:1;1098;1091:12;1071:34;1156:7;1149:4;1139:6;1136:1;1132:14;1128:2;1124:23;1120:34;1117:47;1114:67;;;1177:1;1174;1167:12;1114:67;1208:4;1204:2;1200:13;1190:23;;1232:6;1222:16;;;1257:40;1291:4;1280:9;1276:20;1257:40;:::i;:::-;1247:50;;1350:2;1339:9;1335:18;1322:32;1306:48;;1379:2;1369:8;1366:16;1363:36;;;1395:1;1392;1385:12;1363:36;;1434:60;1486:7;1475:8;1464:9;1460:24;1434:60;:::i;:::-;544:1010;;;;-1:-1:-1;544:1010:32;;-1:-1:-1;1513:8:32;;1408:86;544:1010;-1:-1:-1;;;544:1010:32:o;1668:257::-;1709:3;1747:5;1741:12;1774:6;1769:3;1762:19;1790:63;1846:6;1839:4;1834:3;1830:14;1823:4;1816:5;1812:16;1790:63;:::i;:::-;1907:2;1886:15;-1:-1:-1;;1882:29:32;1873:39;;;;1914:4;1869:50;;1668:257;-1:-1:-1;;1668:257:32:o;1930:274::-;2059:3;2097:6;2091:13;2113:53;2159:6;2154:3;2147:4;2139:6;2135:17;2113:53;:::i;:::-;2182:16;;;;;1930:274;-1:-1:-1;;1930:274:32:o;2209:2090::-;2477:4;2506:2;2546;2535:9;2531:18;2576:2;2565:9;2558:21;2599:6;2634;2628:13;2665:6;2657;2650:22;2691:3;2681:13;;2725:2;2714:9;2710:18;2703:25;;2787:2;2777:6;2774:1;2770:14;2759:9;2755:30;2751:39;2809:4;2848:2;2840:6;2836:15;2869:1;2879:1249;2893:6;2890:1;2887:13;2879:1249;;;2958:22;;;-1:-1:-1;;2954:37:32;2942:50;;3015:13;;3102:9;;-1:-1:-1;;;;;3098:35:32;3083:51;;3173:11;;;3167:18;3055:15;;;;3225:1;3208:19;;3198:170;;3278:10;3273:3;3269:20;3266:1;3259:31;3317:4;3314:1;3307:15;3349:4;3346:1;3339:15;3198:170;3388:15;;;3381:37;3441:4;3486:11;;;3480:18;3518:15;;;3511:27;;;3599:21;;3633:24;;;;3723:23;;;;-1:-1:-1;;3679:15:32;;;;3784:236;3800:8;3795:3;3792:17;3784:236;;;3881:15;;-1:-1:-1;;;;;;3877:42:32;3863:57;;3989:17;;;;3828:1;3819:11;;;;;3946:14;;;;3784:236;;;-1:-1:-1;4106:12:32;;;;4043:5;-1:-1:-1;;;4071:15:32;;;;2915:1;2908:9;2879:1249;;;-1:-1:-1;;;;;;;1625:31:32;;4164:18;;;1613:44;4221:22;;;4214:4;4199:20;;4192:52;4261:32;4225:6;4278;4261:32;:::i;:::-;4253:40;2209:2090;-1:-1:-1;;;;;;;;;;2209:2090:32:o;4304:219::-;4453:2;4442:9;4435:21;4416:4;4473:44;4513:2;4502:9;4498:18;4490:6;4473:44;:::i;:::-;4465:52;4304:219;-1:-1:-1;;;4304:219:32:o;5767:407::-;5969:2;5951:21;;;6008:2;5988:18;;;5981:30;6047:34;6042:2;6027:18;;6020:62;-1:-1:-1;;;6113:2:32;6098:18;;6091:41;6164:3;6149:19;;5767:407::o;7011:408::-;7213:2;7195:21;;;7252:2;7232:18;;;7225:30;7291:34;7286:2;7271:18;;7264:62;-1:-1:-1;;;7357:2:32;7342:18;;7335:42;7409:3;7394:19;;7011:408::o;9539:253::-;9611:2;9605:9;9653:4;9641:17;;9688:18;9673:34;;9709:22;;;9670:62;9667:88;;;9735:18;;:::i;:::-;9771:2;9764:22;9539:253;:::o;9797:275::-;9868:2;9862:9;9933:2;9914:13;;-1:-1:-1;;9910:27:32;9898:40;;9968:18;9953:34;;9989:22;;;9950:62;9947:88;;;10015:18;;:::i;:::-;10051:2;10044:22;9797:275;;-1:-1:-1;9797:275:32:o;10077:182::-;10136:4;10169:18;10161:6;10158:30;10155:56;;;10191:18;;:::i;:::-;-1:-1:-1;10236:1:32;10232:14;10248:4;10228:25;;10077:182::o;10264:125::-;10304:4;10332:1;10329;10326:8;10323:34;;;10337:18;;:::i;:::-;-1:-1:-1;10374:9:32;;10264:125::o;10394:2213::-;10564:9;10599:63;10615:46;10654:6;10615:46;:::i;:::-;10599:63;:::i;:::-;10696:19;;;10734:4;10754:12;;;;10684:3;10786:5;10810:1;10855:14;10837:15;;;10826:27;;10823:47;10820:67;;;10883:1;10880;10873:12;10820:67;10905:1;10915:1659;10929:6;10926:1;10923:13;10915:1659;;;11010:3;10997:17;11037:18;11087:2;11074:11;11071:19;11068:39;;;11103:1;11100;11093:12;11068:39;11141:11;11134:5;11130:23;11120:33;;11198:4;11193:2;11177:14;11173:23;11169:34;11166:54;;;11216:1;11213;11206:12;11166:54;11248:22;;:::i;:::-;11299;11318:2;11299:22;:::i;:::-;11290:7;11283:39;11371:2;11367;11363:11;11350:25;11410:1;11401:7;11398:14;11388:42;;11426:1;11423;11416:12;11388:42;11450:16;;;11443:33;11499:2;11541:11;;;11528:25;11569:14;;;11566:34;;;11596:1;11593;11586:12;11566:34;11623:15;;;;;11680:14;11673:4;11665:13;;11661:34;11651:62;;11709:1;11706;11699:12;11651:62;11749:2;11736:16;11726:26;;11778:59;11794:42;11833:2;11794:42;:::i;11778:59::-;11881:17;;;11920:14;;;;11960:11;;;12021:14;12002:11;;;11994:20;;11990:29;;11987:49;11984:69;;;12049:1;12046;12039:12;11984:69;12077:1;12066:12;;12091:332;12107:2;12102:3;12099:11;12091:332;;;12179:19;;-1:-1:-1;;;;;;12237:34:32;;12225:47;;12215:75;;12286:1;12283;12276:12;12215:75;12307:22;;12129:1;12120:11;;;;;12355:14;;;;12395;;12091:332;;;-1:-1:-1;12443:16:32;;;12436:31;;;;-1:-1:-1;12480:20:32;;-1:-1:-1;;12520:12:32;;;;12552;;;;10951:1;10944:9;10915:1659;;;-1:-1:-1;12596:5:32;;10394:2213;-1:-1:-1;;;;;;;10394:2213:32:o;12612:258::-;12684:1;12694:113;12708:6;12705:1;12702:13;12694:113;;;12784:11;;;12778:18;12765:11;;;12758:39;12730:2;12723:10;12694:113;;;12825:6;12822:1;12819:13;12816:48;;;-1:-1:-1;;12860:1:32;12842:16;;12835:27;12612:258::o;12875:135::-;12914:3;-1:-1:-1;;12935:17:32;;12932:43;;;12955:18;;:::i;:::-;-1:-1:-1;13002:1:32;12991:13;;12875:135::o;13015:217::-;13053:3;-1:-1:-1;;;;;13142:2:32;13135:5;13131:14;13169:2;13160:7;13157:15;13154:41;;;13175:18;;:::i;:::-;13224:1;13211:15;;13015:217;-1:-1:-1;;;13015:217:32:o;13237:127::-;13298:10;13293:3;13289:20;13286:1;13279:31;13329:4;13326:1;13319:15;13353:4;13350:1;13343:15;13369:127;13430:10;13425:3;13421:20;13418:1;13411:31;13461:4;13458:1;13451:15;13485:4;13482:1;13475:15;13501:127;13562:10;13557:3;13553:20;13550:1;13543:31;13593:4;13590:1;13583:15;13617:4;13614:1;13607:15;13633:127;13694:10;13689:3;13685:20;13682:1;13675:31;13725:4;13722:1;13715:15;13749:4;13746:1;13739:15;13765:127;13826:10;13821:3;13817:20;13814:1;13807:31;13857:4;13854:1;13847:15;13881:4;13878:1;13871:15
Swarm Source
ipfs://cb3608f985e15fe1c810d3b025db6fcab323b52b076c5ed6b949dd3015c7d6a5
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.