Polygon Sponsored slots available. Book your slot here!
Overview
POL Balance
0 POL
POL Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
PositionDescriptor
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "base64-sol/base64.sol"; import "./interfaces/IPositionManager.sol"; import "./interfaces/IPositionDescriptor.sol"; import "./lib/Errors.sol"; contract PositionDescriptor is IPositionDescriptor { mapping(bytes32 => string) internal _poolIdentifiers; /** * @notice Get the pool identifier corresponding to the input pool hash * @param poolHash The identifier of the pool **/ function getPoolIdentifier(bytes32 poolHash) public view override returns (string memory) { return _poolIdentifiers[poolHash]; } /** * @notice Set the pool string identifier corresponding to the input pool hash * @param poolIdentifier The string identifier to associate with the corresponding pool hash * @param poolHash The identifier of the pool **/ function setPoolIdentifier(string calldata poolIdentifier, bytes32 poolHash) public override { if (keccak256(abi.encode(poolIdentifier)) != poolHash) { revert Errors.POD_BAD_INPUT(); } _poolIdentifiers[poolHash] = poolIdentifier; emit SetPoolIdentifier(poolIdentifier, poolHash); } /** * @notice Returns the encoded svg for positions artwork * @param position The address of the position manager contract * @param tokenId The tokenId of the position **/ function tokenURI(IPositionManager position, uint128 tokenId) public view override returns (string memory) { (bytes32 poolHash, , uint128 rate, address underlyingToken, , , ) = position.position(tokenId); (uint128 bondsQuantity, uint128 normalizedDepositedAmount) = position.getPositionRepartition(tokenId); string memory symbol = ERC20Upgradeable(underlyingToken).symbol(); string memory image = Base64.encode( bytes( string( abi.encodePacked( '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" ' 'xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 532 754.5" ' 'style="enable-background:new 0 0 532 754.5;" xml:space="preserve">', generateBackground(), generateArt(), generateAtlendisName(), generatePositionMetadata(tokenId, poolHash, symbol, rate, normalizedDepositedAmount, bondsQuantity), "</svg>" ) ) ) ); return string( abi.encodePacked( "data:application/json;base64,", Base64.encode( abi.encodePacked( '{"name":"Position #', uint2str(tokenId), '",' '"description":"A Position on the Atlendis protocol for pool ', _poolIdentifiers[poolHash], ". This NFT represents your share of the pool, its theoritical price depends on the status of the pool, " " the amount of tokens you originally deposited and the different rewards allocated to it." '"external_url":"https://app.atlendis.io/",' '"image": "data:image/svg+xml;base64,', image, '"}' ) ) ) ); } function uint2str(uint128 _i) internal pure returns (string memory str) { if (_i == 0) { return "0"; } uint128 j = _i; uint128 length; while (j != 0) { length++; j /= 10; } bytes memory bstr = new bytes(length); uint128 k = length; j = _i; while (j != 0) { bstr[--k] = bytes1(uint8(48 + (j % 10))); j /= 10; } str = string(bstr); } function generateBackground() internal pure returns (string memory) { return string( abi.encodePacked( '<style type="text/css">.st1{fill:none;stroke:#777188;stroke-width:0.5;stroke-miterlimit:10;}' ".st2{fill:#777188;}" ".st3{fill:#FFFFFF;}" ".st4{fill:#FCB4E0;}" ".st5{font-family:'Roboto-bold';font-size:16px;}" "</style>" '<radialGradient id="SVGID_1_" cx="253.4884" cy="417.4284" r="373.2191" ' 'gradientTransform="matrix(0.8986 0 0 0.8633 38.203 16.8953)" gradientUnits="userSpaceOnUse">' '<stop offset="0" style="stop-color:#3A003F"/><stop offset="1" style="stop-color:#0A002A"/></radialGradient>' '<path style="fill:url(#SVGID_1_);stroke:#FFFFFF;stroke-width:0.4404;stroke-miterlimit:10;" ' 'd="M0,749.9V4.6C0,2.1,2.1,0,4.6,0h522.8c2.5,0,4.6,2.1,4.6,4.6v745.3c0,2.5-2.1,4.6-4.6,4.6H4.6C2.1,754.5,0,752.4,0,749.9z"/>' '<rect x="27.3" y="61.4" class="st1" width="477.8" height="572.9"/>' '<line class="st1" x1="27.3" y1="538.7" x2="505.1" y2="538.7"/>' '<line class="st1" x1="27.3" y1="443.6" x2="505.1" y2="443.6"/>' '<line class="st1" x1="27.3" y1="348.1" x2="505.1" y2="348.1"/>' '<line class="st1" x1="27.3" y1="252.5" x2="505.1" y2="252.5"/>' '<line class="st1" x1="27.3" y1="157" x2="505.1" y2="157"/>' '<line class="st1" x1="122.8" y1="61.4" x2="122.8" y2="634.3"/>' '<line class="st1" x1="218.4" y1="61.4" x2="218.4" y2="634.3"/>' '<line class="st1" x1="314" y1="61.4" x2="314" y2="634.3"/>' '<line class="st1" x1="409.5" y1="61.4" x2="409.5" y2="634.3"/>' '<circle class="st2" cx="409.5" cy="157" r="5.4"/>' '<circle class="st2" cx="505.1" cy="347.8" r="5.4"/>' '<circle class="st2" cx="27.3" cy="538.7" r="5.4"/>' '<circle class="st2" cx="27.3" cy="156.4" r="5.4"/>' ) ); } function generateArt() internal pure returns (string memory) { return string(abi.encodePacked(generateTopPlanets(), generateCenterPlanets(), generateDownPlanets())); } function generateTopPlanets() internal pure returns (string memory) { return string( abi.encodePacked( '<linearGradient id="1" gradientUnits="userSpaceOnUse" x1="502.8664" y1="485.6057" x2="587.8019" ' 'y2="485.6057" gradientTransform="matrix(-0.7096 -0.7046 0.7046 -0.7096 147.9199 858.1921)">' '<stop offset="0" style="stop-color:#FAB2DE"/><stop offset="1" style="stop-color:#0000FF"/>' '</linearGradient><circle style="fill:url(#1);" cx="103.1" cy="129.4" r="42.5"/>' '<linearGradient id="2" gradientUnits="userSpaceOnUse" x1="4853.835" y1="984.5833" x2="4854.8218" ' 'y2="1023.5588" gradientTransform="matrix(-0.9772 -0.2123 0.2123 -0.9772 4667.0605 2228.1553)">' '<stop offset="0" style="stop-color:#00FFFF"/><stop offset="1" style="stop-color:#FFFF00"/>' '</linearGradient><circle style="fill:url(#2);" cx="136.7" cy="215.3" r="19"/>' '<linearGradient id="3" gradientUnits="userSpaceOnUse" x1="697.1088" y1="685.6257" x2="784.6827" ' 'y2="685.6257" gradientTransform="matrix(-2.0426 0.6767 -0.7431 -0.8353 2272.0312 264.6844)">' '<stop offset="0" style="stop-color:#00FFFF"/><stop offset="1" style="stop-color:#9DFC92"/></linearGradient>' '<line style="fill:none;stroke:url(#3);stroke-width:4.142;stroke-linecap:round;stroke-linejoin:round;' 'stroke-miterlimit:10;" x1="342.6" y1="174.2" x2="155.9" y2="212.4"/><linearGradient id="4" ' 'gradientUnits="userSpaceOnUse" x1="348.7628" y1="119.7764" x2="350.8899" y2="203.7983">' '<stop offset="0" style="stop-color:#00FFFF"/><stop offset="1" style="stop-color:#0000FF"/>' '</linearGradient><circle style="fill:url(#4);" cx="350" cy="166.8" r="41"/><circle style="fill:#FFFF00;" ' 'cx="354.8" cy="70" r="5.9"/>' '<linearGradient id="5" gradientUnits="userSpaceOnUse" x1="140.7756" y1="230.1122" x2="228.9412" y2="230.1122">' '<stop offset="0" style="stop-color:#9DFC92"/><stop offset="1" style="stop-color:#FF7BAC"/></linearGradient>' '<line style="fill:none;stroke:url(#5);stroke-width:4.7337;stroke-linecap:round;stroke-linejoin:round;' 'stroke-miterlimit:10;" x1="143.1" y1="219.2" x2="226.6" y2="241.1"/>' '<linearGradient id="6" gradientUnits="userSpaceOnUse" x1="695.0284" y1="812.7755" x2="783.7858" ' 'y2="812.7755" gradientTransform="matrix(-1.1737 0.9697 -0.8244 -0.6412 1822.474 11.7986)">', '<stop offset="0" style="stop-color:#353DF7"/><stop offset="1" style="stop-color:#FF7BAC"/></linearGradient>' '<line style="fill:none;stroke:url(#6);stroke-width:5.3254;stroke-linecap:round;stroke-linejoin:' 'round;stroke-miterlimit:10;" x1="342.6" y1="174.2" x2="226.6" y2="241.1"/>' ) ); } function generateCenterPlanets() internal pure returns (string memory) { return string( abi.encodePacked( '<circle style="fill:#0000FF" cx="114" cy="320" r="38"/>' '<linearGradient id="7" gradientUnits="userSpaceOnUse" x1="279.8008" y1="1203.038" x2="578.9129" ' 'y2="1203.038" gradientTransform="matrix(0 1 -1 0 1444.4052 -54.4462)">' '<stop offset="0" style="stop-color:#FAB2DE"/><stop offset="1" style="stop-color:#0000FF"/>' '</linearGradient><circle style="fill:url(#7);" cx="241.4" cy="374.9" r="149.6"/>' '<linearGradient id="8" gradientUnits="userSpaceOnUse" x1="202.9501" y1="390.4209" x2="109.6353" y2="483.7357">' '<stop offset="0" style="stop-color:#0B0443"/><stop offset="0.5173" style="stop-color:#1B1464"/>' '<stop offset="1" style="stop-color:#2E3190"/></linearGradient>' '<path style="fill:url(#8);" d="M207.8,399.6c27.7,41.8,31.5,88,8.6,103.2c-23,' '15.2-64-6.3-91.7-48.1s-31.5-88-8.6-103.2C139,336.3,180.1,357.9,207.8,399.6z"/>' '<linearGradient id="9" gradientUnits="userSpaceOnUse" x1="705.8905" y1="841.9223" x2="797.4905" ' 'y2="841.9223" gradientTransform="matrix(-0.7071 0.7071 -0.7071 -0.7071 1263.1495 522.8206)">' '<stop offset="0.2165" style="stop-color:#FAB2DE"/><stop offset="1" style="stop-color:#00FFFF"/>' '</linearGradient><circle style="fill:url(#9);" cx="136.3" cy="459" r="45.8"/>' '<linearGradient id="10" gradientUnits="userSpaceOnUse" x1="1589.9778" y1="817.77" x2="1605.3485" ' 'y2="860.5405" gradientTransform="matrix(-0.9832 -0.1825 0.1825 -0.9832 1799.8251 1471.0231)">' '<stop offset="0" style="stop-color:#0B0443"/><stop offset="0.5173" style="stop-color:#1B1464"/>' '<stop offset="1" style="stop-color:#2E3190"/></linearGradient><circle style="fill:url(#10);" cx="381.4" cy="349.8" r="22.1"/>' '<linearGradient id="11" gradientUnits="userSpaceOnUse" x1="225.6964" y1="201.0739" x2="227.4934" y2="272.0549">' '<stop offset="0" style="stop-color:#FC6EC0"/><stop offset="1" style="stop-color:#9C005D"/>' '</linearGradient><circle style="fill:url(#11);" cx="226.7" cy="240.8" r="34.7"/>' ) ); } function generateDownPlanets() internal pure returns (string memory) { return string( abi.encodePacked( '<linearGradient id="12" gradientUnits="userSpaceOnUse" x1="484.1273" y1="295.5512" x2="485.3994" ' 'y2="345.7959" gradientTransform="matrix(0.9045 0.4266 -0.4266 0.9045 193.3309 -47.055)">' '<stop offset="0" style="stop-color:#FC6EC0"/><stop offset="1" style="stop-color:#9C005D"/>' '</linearGradient><circle style="fill:url(#12);" cx="493.8" cy="452.5" r="24.5"/>' '<linearGradient id="13" gradientUnits="userSpaceOnUse" x1="528.0872" y1="444.3404" x2="529.0894" ' 'y2="483.9227" gradientTransform="matrix(0.9045 0.4266 -0.4266 0.9045 193.3309 -47.055)">' '<stop offset="0" style="stop-color:#00FFFF"/><stop offset="1" style="stop-color:#0000FF"/>' '</linearGradient><circle style="fill:url(#13);" cx="472.5" cy="600.4" r="19.3"/>' '<linearGradient id="14" gradientUnits="userSpaceOnUse" x1="1017.4314" y1="453.2621" x2="1106.1887" ' 'y2="453.2621" gradientTransform="matrix(-0.8497 0.1398 -8.259396e-02 -0.9876 1369.6598 893.7979)">' '<stop offset="0" style="stop-color:#4C6FF5"/><stop offset="0.3634" style="stop-color:#4A4FD1"/>' '<stop offset="1" style="stop-color:#45108A"/></linearGradient>' '<line style="fill:none;stroke:url(#14);stroke-width:5.3254;stroke-linecap:round;stroke-linejoin:round;' 'stroke-miterlimit:10;" x1="466.4" y1="599.5" x2="393.7" y2="589.6"/>' '<linearGradient id="15" gradientUnits="userSpaceOnUse" x1="545.4843" y1="617.3547" x2="634.2416" ' 'y2="617.3547" gradientTransform="matrix(-1.1943 1.5673 -1.0482 -0.316 1778.2054 -209.5829)">' '<stop offset="0" style="stop-color:#AA4688"/><stop offset="1" style="stop-color:#353DF7"/></linearGradient>' '<line style="fill:none;stroke:url(#15);stroke-width:5.3254;stroke-linecap:round;stroke-linejoin:round;' 'stroke-miterlimit:10;" x1="487.9" y1="457.9" x2="365.3" y2="581.7"/>' '<linearGradient id="16" gradientUnits="userSpaceOnUse" x1="423.5873" y1="549.3148" x2="424.7167" ' 'y2="443.1502" gradientTransform="matrix(0.9045 0.4266 -0.4266 0.9045 193.3309 -47.055)">', '<stop offset="9.595960e-02" style="stop-color:#381077"/><stop offset="1" style="stop-color:#7C1DC9"/>' '</linearGradient><circle style="fill:url(#16);" cx="365.8" cy="581.6" r="39.3"/>' ) ); } function generateAtlendisName() internal pure returns (string memory) { return string( abi.encodePacked( '<path class="st3" d="M378.2,30.5l5.4,19.1h-2.3l-0.8-3.1H376l-0.8,3.1h-2.3L378.2,' '30.5z M380,44.5l-1.2-4.8l-0.5-2.2l-0.5,2.2l-1.3,4.8H380z"/>' '<path class="st3" d="M395.2,33.1h-2.9V31h8v2.1h-2.9v16.5h-2.2V33.1z"/>' '<path class="st3" d="M410.6,31h2.2v16.5h4.8v2h-7V31z"/>' '<path class="st3" d="M427.5,31h6.2v2.1h-4.1v7.1h3.5v2.1h-3.5v5.3h4.1v2.1h-6.2V31z"/>' '<path class="st3" d="M444.6,30.3l5.8,9.7l1.3,2.3l-0.1-2.2V31h2.2v19l-5.9-9.7l-1.3-2l0.1,2v9.3h-2.2V30.3z"/>' '<path class="st3" d="M465.3,30.8c1.3,0.1,2.4,0.3,3.5,0.8c1,0.5,1.9,1.1,2.7,1.9c0.7,0.8,1.3,1.8,1.7,' "2.9c0.4,1.1,0.6,2.4,0.6,3.9c0,1.4-0.2,2.7-0.6,3.9c-0.4,1.1-1,2.1-1.7,2.9c-0.7,0.8-1.6,1.4-2.7,1.9c-1,0.5-2.2," "0.7-3.5,0.8V30.8z M467.5,47.3c0.5-0.2,1-0.4,1.5-0.7c0.5-0.3,0.9-0.8,1.3-1.4c0.4-0.6,0.7-1.2,0.9-2c0.2-0.8,0.4-1.8," '0.4-2.8c0-1.1-0.1-2-0.4-2.8c-0.2-0.8-0.5-1.5-0.9-2c-0.4-0.6-0.8-1-1.3-1.4c-0.5-0.3-1-0.6-1.5-0.7V47.3z"/>' '<path class="st3" d="M484.4,31h2.2v18.6h-2.2V31z"/>' '<path class="st3" d="M498,46.8c0.4,0.2,0.8,0.4,1.2,0.6c0.4,0.2,0.9,0.3,1.4,0.3c0.3,0,0.6,0,0.9-0.1s0.5-0.2,0.7-0.4' "c0.2-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.2-0.6,0.2-1c0-0.3,0-0.5-0.1-0.8c-0.1-0.3-0.2-0.6-0.3-0.9c-0.2-0.3-0.3-0.7-0.6-1" "c-0.2-0.4-0.5-0.8-0.9-1.2l-1.5-1.9c-0.4-0.5-0.7-0.9-1-1.4c-0.3-0.4-0.5-0.8-0.6-1.2c-0.2-0.4-0.3-0.8-0.4-1.1" "c-0.1-0.4-0.1-0.7-0.1-1.1c0-0.6,0.1-1.1,0.3-1.6c0.2-0.5,0.5-0.9,0.8-1.3c0.4-0.4,0.8-0.6,1.3-0.8c0.5-0.2,1.1-0.3,1.7-0.3" "c0.5,0,1,0.1,1.6,0.2c0.5,0.1,1,0.4,1.5,0.6l-0.9,1.8c-0.3-0.2-0.6-0.3-0.9-0.4c-0.3-0.1-0.7-0.2-1-0.2c-0.6,0-1.1,0.2-1.5,0.5" "c-0.4,0.4-0.6,0.9-0.6,1.5c0,0.2,0,0.4,0.1,0.6c0,0.2,0.1,0.4,0.2,0.6c0.1,0.2,0.2,0.5,0.4,0.7c0.2,0.3,0.4,0.6,0.6,0.9l2.2,2.9" "c0.3,0.4,0.5,0.7,0.8,1.1c0.2,0.4,0.5,0.7,0.6,1.1c0.2,0.4,0.3,0.8,0.4,1.2c0.1,0.4,0.2,0.8,0.2,1.3c0,0.7-0.1,1.3-0.3,1.9" "c-0.2,0.6-0.5,1-0.9,1.4c-0.4,0.4-0.9,0.7-1.4,0.9c-0.6,0.2-1.2,0.3-1.8,0.3c-0.7,0-1.3-0.1-2-0.3c-0.6-0.2-1.2-0.5-1.6-0.8" 'L498,46.8z"/>' ) ); } function generatePositionMetadata( uint128 tokenId, bytes32 poolHash, string memory symbol, uint128 rate, uint128 normalizedDepositedAmount, uint128 bondsQuantity ) internal view returns (string memory) { return string( abi.encodePacked( generatePositionId(tokenId), generatePoolName(poolHash), generatePoolRate(rate), generatePoolAmounts(symbol, normalizedDepositedAmount, bondsQuantity) ) ); } function generatePositionId(uint128 tokenId) internal pure returns (string memory) { return string( abi.encodePacked( '<linearGradient id="17" gradientUnits="userSpaceOnUse" x1="38.7172" y1="2.7463" x2="102.529" y2="66.5581">' '<stop offset="0.2165" style="stop-color:#FAB2DE"/><stop offset="1" style="stop-color:#00FFFF"/></linearGradient>' '<path style="fill:url(#17);" d="M121.2,54.1H28.8c-0.9,0-1.7-0.7-1.7-1.7V25.5c0-0.9,' '0.7-1.7,1.7-1.7h92.4c0.9,0,1.7,0.7,1.7,1.7v26.9C122.8,53.4,122.1,54.1,121.2,54.1z"/>' '<text transform="matrix(1 0 0 1 41.9943 43.7106)" class="st5">ID: ', uint2str(tokenId), "</text>" ) ); } function generatePoolName(bytes32 poolHash) internal view returns (string memory) { string memory poolIdentifier = _poolIdentifiers[poolHash]; return string( abi.encodePacked( '<path class="st1" d="M29.2,642.7h356.7c1.1,0,2.1,1.3,2.1,2.8v24.7c0,1.5-1,2.8-2.1,' '2.8H29.2c-1.1,0-2.1-1.3-2.1-2.8v-24.7C27.1,643.9,28,642.7,29.2,642.7z"/>' '<text transform="matrix(1 0 0 1 37.5065 663.5427)" class="st3 st5">Pool: ', poolIdentifier, "</text>" ) ); } function generatePoolRate(uint128 rate) internal pure returns (string memory) { uint128 firstSignificantNumberPrecision = 1e16; uint128 secondSignificantNumberPrecision = 1e14; return string( abi.encodePacked( '<path class="st1" d="M398.1,642.8h104.5c1.1,0,1.9,0.9,1.9,1.9v26.4c0,1.1-0.9,1.9-1.9,' '1.9H398.1c-1.1,0-1.9-0.9-1.9-1.9v-26.4C396.2,643.7,397.1,642.8,398.1,642.8z"/>' '<text transform="matrix(1 0 0 1 420.3261 662.4679)" class="st3 st5">I.R. ', uint2str(rate / firstSignificantNumberPrecision), ".", uint2str((rate % firstSignificantNumberPrecision) / secondSignificantNumberPrecision), "%</text>" ) ); } function generatePoolAmounts( string memory symbol, uint128 normalizedDepositedAmount, uint128 bondsQuantity ) internal pure returns (string memory) { uint128 firstSignificantNumberPrecision = 1e18; uint128 secondSignificantNumberPrecision = 1e16; return string( abi.encodePacked( '<path class="st1" d="M259.8,711.6H29.9c-1.3,0-2.3-1.6-2.3-3.5v-23.2c0-2,1-3.5,' '2.3-3.5h229.9c1.3,0,2.3,1.6,2.3,3.5v23.2C262.1,710,261,711.6,259.8,711.6z"/>' '<text transform="matrix(1 0 0 1 38.0304 702.1925)" class="st3 st5">', uint2str(normalizedDepositedAmount / firstSignificantNumberPrecision), ".", uint2str((normalizedDepositedAmount % firstSignificantNumberPrecision) / secondSignificantNumberPrecision), symbol, ' Deposited </text><path class="st1" d="M501.8,711.6H271.2c-1.3,0-2.3-1.6-2.3-3.5v-23.2c0-2,' '1-3.5,2.3-3.5h230.7c1.3,0,2.3,1.6,2.3,3.5v23.2C504.1,710,503.1,711.6,501.8,711.6z"/>' '<text transform="matrix(1 0 0 1 278.8931 702.1919)" class="st3 st5">', uint2str(bondsQuantity / firstSignificantNumberPrecision), ".", uint2str((bondsQuantity % firstSignificantNumberPrecision) / secondSignificantNumberPrecision), symbol, " Borrowed </text>" ) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.0; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.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 ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { 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. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _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: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, _allowances[owner][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = _allowances[owner][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, 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: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _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 Spend `amount` form the allowance of `owner` toward `spender`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); /** * @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 // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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 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 // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @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 ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender ; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /// @title Base64 /// @author Brecht Devos - <[email protected]> /// @notice Provides functions for encoding/decoding base64 library Base64 { string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000" hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000" hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000" hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000"; function encode(bytes memory data) internal pure returns (string memory) { if (data.length == 0) return ''; // load the table into memory string memory table = TABLE_ENCODE; // multiply by 4/3 rounded up uint256 encodedLen = 4 * ((data.length + 2) / 3); // add some extra buffer at the end required for the writing string memory result = new string(encodedLen + 32); assembly { // set the actual output length mstore(result, encodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 3 bytes at a time for {} lt(dataPtr, endPtr) {} { // read 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // write 4 characters mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F)))) resultPtr := add(resultPtr, 1) } // padding with '=' switch mod(mload(data), 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } } return result; } function decode(string memory _data) internal pure returns (bytes memory) { bytes memory data = bytes(_data); if (data.length == 0) return new bytes(0); require(data.length % 4 == 0, "invalid base64 decoder input"); // load the table into memory bytes memory table = TABLE_DECODE; // every 4 characters represent 3 bytes uint256 decodedLen = (data.length / 4) * 3; // add some extra buffer at the end required for the writing bytes memory result = new bytes(decodedLen + 32); assembly { // padding with '=' let lastBytes := mload(add(data, mload(data))) if eq(and(lastBytes, 0xFF), 0x3d) { decodedLen := sub(decodedLen, 1) if eq(and(lastBytes, 0xFFFF), 0x3d3d) { decodedLen := sub(decodedLen, 1) } } // set the actual output length mstore(result, decodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 4 characters at a time for {} lt(dataPtr, endPtr) {} { // read 4 characters dataPtr := add(dataPtr, 4) let input := mload(dataPtr) // write 3 bytes let output := add( add( shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)), shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))), add( shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)), and(mload(add(tablePtr, and( input , 0xFF))), 0xFF) ) ) mstore(resultPtr, shl(232, output)) resultPtr := add(resultPtr, 3) } } return result; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; interface ILendingPool { /** * @dev Emitted on deposit() * @param reserve The address of the underlying asset of the reserve * @param user The address initiating the deposit * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens * @param amount The amount deposited * @param referral The referral code used **/ event Deposit( address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint16 indexed referral ); /** * @dev Emitted on withdraw() * @param reserve The address of the underlyng asset being withdrawn * @param user The address initiating the withdrawal, owner of aTokens * @param to Address that will receive the underlying * @param amount The amount to be withdrawn **/ event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); /** * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. * - E.g. User deposits 100 USDC and gets in return 100 aUSDC * @param asset The address of the underlying asset to deposit * @param amount The amount to be deposited * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function deposit( address asset, uint256 amount, address onBehalfOf, uint16 referralCode ) external; /** * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC * @param asset The address of the underlying asset to withdraw * @param amount The underlying amount to be withdrawn * - Send the value type(uint256).max in order to withdraw the whole aToken balance * @param to Address that will receive the underlying, same as msg.sender if the user * wants to receive it on his own wallet, or a different address if the beneficiary is a * different wallet * @return The final amount withdrawn **/ function withdraw( address asset, uint256 amount, address to ) external returns (uint256); /** * @dev Returns the normalized income normalized income of the reserve * @param asset The address of the underlying asset of the reserve * @return The reserve's normalized income */ function getReserveNormalizedIncome(address asset) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import "../extensions/AaveILendingPool.sol"; import "../lib/Types.sol"; /** * @title IBorrowerPools * @notice Used by the Position contract to pool lender positions in the borrowers order books * Used by the borrowers to manage their loans on their pools **/ interface IBorrowerPools { // EVENTS /** * @notice Emitted after a successful borrow * @param poolHash The identifier of the pool * @param normalizedBorrowedAmount The actual amount of tokens borrowed * @param establishmentFees Fees paid to the protocol at borrow time **/ event Borrow(bytes32 indexed poolHash, uint128 normalizedBorrowedAmount, uint128 establishmentFees); /** * @notice Emitted after a successful further borrow * @param poolHash The identifier of the pool * @param normalizedBorrowedAmount The actual amount of tokens borrowed * @param establishmentFees Fees paid to the protocol at borrow time **/ event FurtherBorrow(bytes32 indexed poolHash, uint128 normalizedBorrowedAmount, uint128 establishmentFees); /** * @notice Emitted after a successful repay * @param poolHash The identifier of the pool * @param normalizedRepayAmount The actual amount of tokens repaid * @param repaymentFee The amount of fee paid to the protocol at repay time * @param normalizedDepositsAfterRepay The actual amount of tokens deposited and available for next loan after repay * @param nextLoanMinStart The timestamp after which a new loan can be taken **/ event Repay( bytes32 indexed poolHash, uint128 normalizedRepayAmount, uint128 repaymentFee, uint128 normalizedDepositsAfterRepay, uint128 nextLoanMinStart ); /** * @notice Emitted after a successful early repay * @param poolHash The identifier of the pool * @param normalizedRepayAmount The actual amount of tokens repaid * @param repaymentFee The amount of fee paid to the protocol at repay time * @param normalizedDepositsAfterRepay The actual amount of tokens deposited and available for next loan after repay * @param nextLoanMinStart The timestamp after which a new loan can be taken **/ event EarlyRepay( bytes32 indexed poolHash, uint128 normalizedRepayAmount, uint128 repaymentFee, uint128 normalizedDepositsAfterRepay, uint128 nextLoanMinStart ); /** * @notice Emitted after a successful repay, made after the repayment period * Includes a late repay fee * @param poolHash The identifier of the pool * @param normalizedRepayAmount The actual amount of tokens repaid * @param lateRepayFee The amount of fee paid due to a late repayment * @param repaymentFee The amount of fee paid to the protocol at repay time * @param normalizedDepositsAfterRepay The actual amount of tokens deposited and available for next loan after repay * @param nextLoanMinStart The timestamp after which a new loan can be taken **/ event LateRepay( bytes32 indexed poolHash, uint128 normalizedRepayAmount, uint128 lateRepayFee, uint128 repaymentFee, uint128 normalizedDepositsAfterRepay, uint128 nextLoanMinStart ); /** * @notice Emitted after a borrower successfully deposits tokens in its pool liquidity rewards reserve * @param poolHash The identifier of the pool * @param normalizedAmount The actual amount of tokens deposited into the reserve **/ event TopUpLiquidityRewards(bytes32 poolHash, uint128 normalizedAmount); // The below events and enums are being used in the PoolLogic library // The same way that libraries don't have storage, they don't have an event log // Hence event logs will be saved in the calling contract // For the contract abi to reflect this and be used by offchain libraries, // we define these events and enums in the contract itself as well /** * @notice Emitted when a tick is initialized, i.e. when its first deposited in * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param atlendisLiquidityRatio The tick current liquidity index **/ event TickInitialized(bytes32 poolHash, uint128 rate, uint128 atlendisLiquidityRatio); /** * @notice Emitted after a deposit on a tick that was done during a loan * @param poolHash The identifier of the pool * @param rate The position bidding rate * @param adjustedPendingDeposit The amount of tokens deposited during a loan, adjusted to the current liquidity index **/ event TickLoanDeposit(bytes32 poolHash, uint128 rate, uint128 adjustedPendingDeposit); /** * @notice Emitted after a deposit on a tick that was done without an active loan * @param poolHash The identifier of the pool * @param rate The position bidding rate * @param adjustedAvailableDeposit The amount of tokens available to the borrower for its next loan * @param atlendisLiquidityRatio The tick current liquidity index **/ event TickNoLoanDeposit( bytes32 poolHash, uint128 rate, uint128 adjustedAvailableDeposit, uint128 atlendisLiquidityRatio ); /** * @notice Emitted when a borrow successfully impacts a tick * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param adjustedRemainingAmountReduction The amount of tokens left to borrow from other ticks * @param loanedAmount The amount borrowed from the tick * @param atlendisLiquidityRatio The tick current liquidity index * @param unborrowedRatio Proportion of ticks funds that were not borrowed **/ event TickBorrow( bytes32 poolHash, uint128 rate, uint128 adjustedRemainingAmountReduction, uint128 loanedAmount, uint128 atlendisLiquidityRatio, uint128 unborrowedRatio ); /** * @notice Emitted when a withdraw is done outside of a loan on the tick * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param adjustedAmountToWithdraw The amount of tokens to withdraw, adjusted to the tick liquidity index **/ event TickWithdrawPending(bytes32 poolHash, uint128 rate, uint128 adjustedAmountToWithdraw); /** * @notice Emitted when a withdraw is done during a loan on the tick * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param adjustedAmountToWithdraw The amount of tokens to withdraw, adjusted to the tick liquidity index * @param atlendisLiquidityRatio The tick current liquidity index * @param accruedFeesToWithdraw The amount of fees the position has a right to claim **/ event TickWithdrawRemaining( bytes32 poolHash, uint128 rate, uint128 adjustedAmountToWithdraw, uint128 atlendisLiquidityRatio, uint128 accruedFeesToWithdraw ); /** * @notice Emitted when pending amounts are merged with the rest of the pool during a repay * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param adjustedPendingAmount The amount of pending funds deposited with available funds **/ event TickPendingDeposit( bytes32 poolHash, uint128 rate, uint128 adjustedPendingAmount, bool poolBondIssuanceIndexIncremented ); /** * @notice Emitted when funds from a tick are repaid by the borrower * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param adjustedRemainingAmount The total amount of tokens available to the borrower for * its next loan, adjusted to the tick current liquidity index * @param atlendisLiquidityRatio The tick current liquidity index **/ event TickRepay(bytes32 poolHash, uint128 rate, uint128 adjustedRemainingAmount, uint128 atlendisLiquidityRatio); /** * @notice Emitted when liquidity rewards are distributed to a tick * @param poolHash The identifier of the pool * @param rate The tick's bidding rate * @param remainingLiquidityRewards the amount of liquidityRewards added to the tick * @param addedAccruedFees Increase in accrued fees for that tick **/ event CollectFeesForTick(bytes32 poolHash, uint128 rate, uint128 remainingLiquidityRewards, uint128 addedAccruedFees); // VIEW METHODS /** * @notice Returns the liquidity ratio of a given tick in a pool's order book. * The liquidity ratio is an accounting construct to deduce the accrued interest over time. * @param poolHash The identifier of the pool * @param rate The tick rate from which to extract the liquidity ratio * @return liquidityRatio The liquidity ratio of the given tick **/ function getTickLiquidityRatio(bytes32 poolHash, uint128 rate) external view returns (uint128 liquidityRatio); /** * @notice Returns the repartition between bonds and deposits of the given tick. * @param poolHash The identifier of the pool * @param rate The tick rate from which to get data * @return adjustedTotalAmount Total amount of deposit in the tick * @return adjustedRemainingAmount Amount of tokens in tick deposited with the * underlying yield provider that were deposited before bond issuance * @return bondsQuantity The quantity of bonds within the tick * @return adjustedPendingAmount Amount of deposit in tick deposited with the * underlying yield provider that were deposited after bond issuance * @return atlendisLiquidityRatio The liquidity ratio of the given tick * @return accruedFees The total fees claimable in the current tick, either from * yield provider interests or liquidity rewards accrual **/ function getTickAmounts(bytes32 poolHash, uint128 rate) external view returns ( uint128 adjustedTotalAmount, uint128 adjustedRemainingAmount, uint128 bondsQuantity, uint128 adjustedPendingAmount, uint128 atlendisLiquidityRatio, uint128 accruedFees ); /** * @notice Returns the timestamp of the last fee distribution to the tick * @param poolHash The identifier of the pool * @param rate The tick rate from which to get data * @return lastFeeDistributionTimestamp Timestamp of the last fee's distribution to the tick **/ function getTickLastUpdate(string calldata poolHash, uint128 rate) external view returns (uint128 lastFeeDistributionTimestamp); /** * @notice Returns the current state of the pool's parameters * @param poolHash The identifier of the pool * @return weightedAverageLendingRate The average deposit bidding rate in the order book * @return adjustedPendingDeposits Amount of tokens deposited after bond * issuance and currently on third party yield provider **/ function getPoolAggregates(bytes32 poolHash) external view returns (uint128 weightedAverageLendingRate, uint128 adjustedPendingDeposits); /** * @notice Returns the current maturity of the pool * @param poolHash The identifier of the pool * @return poolCurrentMaturity The pool's current maturity **/ function getPoolMaturity(bytes32 poolHash) external view returns (uint128 poolCurrentMaturity); /** * @notice Estimates the lending rate corresponding to the input amount, * depending on the current state of the pool * @param normalizedBorrowedAmount The amount to be borrowed from the pool * @param poolHash The identifier of the pool * @return estimatedRate The estimated loan rate for the current state of the pool **/ function estimateLoanRate(uint128 normalizedBorrowedAmount, bytes32 poolHash) external view returns (uint128 estimatedRate); /** * @notice Returns the token amount's repartition between bond quantity and normalized * deposited amount currently placed on third party yield provider * @param poolHash The identifier of the pool * @param rate Tick's rate * @param adjustedAmount Adjusted amount of tokens currently on third party yield provider * @param bondsIssuanceIndex The identifier of the borrow group * @return bondsQuantity Quantity of bonds held * @return normalizedDepositedAmount Amount of deposit currently on third party yield provider **/ function getAmountRepartition( bytes32 poolHash, uint128 rate, uint128 adjustedAmount, uint128 bondsIssuanceIndex ) external view returns (uint128 bondsQuantity, uint128 normalizedDepositedAmount); /** * @notice Returns the total amount a borrower has to repay to a pool. Includes borrowed * amount, late repay fees and protocol fees * @param poolHash The identifier of the pool * @param earlyRepay indicates if this is an early repay * @return normalizedRepayAmount Total repay amount * @return lateRepayFee Normalized amount to be paid to each bond in case of late repayment * @return repaymentFee Normalized fee amount paid to the protocol **/ function getRepayAmounts(bytes32 poolHash, bool earlyRepay) external view returns ( uint128 normalizedRepayAmount, uint128 lateRepayFee, uint128 repaymentFee ); // LENDER METHODS /** * @notice Gets called within the Position.deposit() function and enables a lender to deposit assets * into a given borrower's order book. The lender specifies a rate (price) at which it is willing to * lend out its assets (bid on the zero coupon bond). The full amount will initially be deposited * on the underlying yield provider until the borrower sells bonds at the specified rate. * @param normalizedAmount The amount of the given asset to deposit * @param rate The rate at which to bid for a bond * @param poolHash The identifier of the pool * @param underlyingToken Contract' address of the token to be deposited * @param sender The lender address who calls the deposit function on the Position * @return adjustedAmount Deposited amount adjusted with current liquidity index * @return bondsIssuanceIndex The identifier of the borrow group to which the deposit has been allocated **/ function deposit( uint128 rate, bytes32 poolHash, address underlyingToken, address sender, uint128 normalizedAmount ) external returns (uint128 adjustedAmount, uint128 bondsIssuanceIndex); /** * @notice Gets called within the Position.withdraw() function and enables a lender to * evaluate the exact amount of tokens it is allowed to withdraw * @dev This method is meant to be used exclusively with the withdraw() method * Under certain circumstances, this method can return incorrect values, that would otherwise * be rejected by the checks made in the withdraw() method * @param poolHash The identifier of the pool * @param rate The rate the position is bidding for * @param adjustedAmount The amount of tokens in the position, adjusted to the deposit liquidity ratio * @param bondsIssuanceIndex An index determining deposit timing * @return adjustedAmountToWithdraw The amount of tokens to withdraw, adjuste for borrow pool use * @return depositedAmountToWithdraw The amount of tokens to withdraw, adjuste for position use * @return remainingBondsQuantity The quantity of bonds remaining within the position * @return bondsMaturity The maturity of bonds remaining within the position after withdraw **/ function getWithdrawAmounts( bytes32 poolHash, uint128 rate, uint128 adjustedAmount, uint128 bondsIssuanceIndex ) external view returns ( uint128 adjustedAmountToWithdraw, uint128 depositedAmountToWithdraw, uint128 remainingBondsQuantity, uint128 bondsMaturity ); /** * @notice Gets called within the Position.withdraw() function and enables a lender to * withdraw assets that are deposited with the underlying yield provider * @param poolHash The identifier of the pool * @param rate The rate the position is bidding for * @param adjustedAmountToWithdraw The actual amount of tokens to withdraw from the position * @param bondsIssuanceIndex An index determining deposit timing * @param owner The address to which the withdrawns funds are sent * @return normalizedDepositedAmountToWithdraw Actual amount of tokens withdrawn and sent to the lender **/ function withdraw( bytes32 poolHash, uint128 rate, uint128 adjustedAmountToWithdraw, uint128 bondsIssuanceIndex, address owner ) external returns (uint128 normalizedDepositedAmountToWithdraw); /** * @notice Gets called within Position.updateRate() and updates the order book ticks affected by the position * updating its rate. This is only possible as long as there are no bonds in the position, i.e the full * position currently lies with the yield provider * @param adjustedAmount The adjusted balance of tokens of the given position * @param poolHash The identifier of the pool * @param oldRate The current rate of the position * @param newRate The new rate of the position * @param oldBondsIssuanceIndex The identifier of the borrow group from the given position * @return newAdjustedAmount The updated amount of tokens of the position adjusted by the * new tick's global liquidity ratio * @return newBondsIssuanceIndex The new borrow group id to which the updated position is linked **/ function updateRate( uint128 adjustedAmount, bytes32 poolHash, uint128 oldRate, uint128 newRate, uint128 oldBondsIssuanceIndex ) external returns ( uint128 newAdjustedAmount, uint128 newBondsIssuanceIndex, uint128 normalizedAmount ); // BORROWER METHODS /** * @notice Called by the borrower to sell bonds to the order book. * The affected ticks get updated according the amount of bonds sold. * @param to The address to which the borrowed funds should be sent. * @param loanAmount The total amount of the loan **/ function borrow(address to, uint128 loanAmount) external; /** * @notice Repays a currently outstanding bonds of the given borrower. **/ function repay() external; /** * @notice Called by the borrower to top up liquidity rewards' reserve that * is distributed to liquidity providers at the pre-defined distribution rate. * @param normalizedAmount Amount of tokens that will be add up to the borrower's liquidity rewards reserve **/ function topUpLiquidityRewards(uint128 normalizedAmount) external; // FEE COLLECTION /** * @notice Collect yield provider fees as well as liquidity rewards for the target tick * @param poolHash The identifier of the pool **/ function collectFeesForTick(bytes32 poolHash, uint128 rate) external; /** * @notice Collect yield provider fees as well as liquidity rewards for the whole pool * Iterates over all pool initialized ticks * @param poolHash The identifier of the pool **/ function collectFees(bytes32 poolHash) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import "./IPositionManager.sol"; /** * @title IPositionDescriptor * @notice Generates the SVG artwork for lenders positions **/ interface IPositionDescriptor { /** * @notice Emitted after the string identifier of a pool has been set * @param poolIdentifier The string identifier of the pool * @param poolHash The hash identifier of the pool **/ event SetPoolIdentifier(string poolIdentifier, bytes32 poolHash); /** * @notice Get the pool identifier corresponding to the input pool hash * @param poolHash The identifier of the pool **/ function getPoolIdentifier(bytes32 poolHash) external view returns (string memory); /** * @notice Set the pool string identifier corresponding to the input pool hash * @param poolIdentifier The string identifier to associate with the corresponding pool hash * @param poolHash The identifier of the pool **/ function setPoolIdentifier(string calldata poolIdentifier, bytes32 poolHash) external; /** * @notice Returns the encoded svg for positions artwork * @param position The address of the position manager contract * @param tokenId The tokenId of the position **/ function tokenURI(IPositionManager position, uint128 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import "./IBorrowerPools.sol"; /** * @title IPositionManager * @notice Contains methods that can be called by lenders to create and manage their position **/ interface IPositionManager { /** * @notice Emitted when #deposit is called and is a success * @param lender The address of the lender depositing token on the protocol * @param tokenId The tokenId of the position * @param amount The amount of deposited token * @param rate The position bidding rate * @param poolHash The identifier of the pool * @param bondsIssuanceIndex The borrow period assigned to the position **/ event Deposit( address indexed lender, uint128 tokenId, uint128 amount, uint128 rate, bytes32 poolHash, uint128 bondsIssuanceIndex ); /** * @notice Emitted when #updateRate is called and is a success * @param lender The address of the lender updating their position * @param tokenId The tokenId of the position * @param amount The amount of deposited token plus their accrued interests * @param rate The new rate required by lender to lend their deposited token * @param poolHash The identifier of the pool **/ event UpdateRate(address indexed lender, uint128 tokenId, uint128 amount, uint128 rate, bytes32 poolHash); /** * @notice Emitted when #withdraw is called and is a success * @param lender The address of the withdrawing lender * @param tokenId The tokenId of the position * @param amount The amount of tokens withdrawn * @param rate The position bidding rate * @param poolHash The identifier of the pool **/ event Withdraw( address indexed lender, uint128 tokenId, uint128 amount, uint128 remainingBonds, uint128 rate, bytes32 poolHash ); /** * @notice Set the position descriptor address * @param positionDescriptor The address of the new position descriptor **/ event SetPositionDescriptor(address positionDescriptor); /** * @notice Emitted when #withdraw is called and is a success * @param tokenId The tokenId of the position * @return poolHash The identifier of the pool * @return adjustedBalance Adjusted balance of the position original deposit * @return rate Position bidding rate * @return underlyingToken Address of the tokens the position contains * @return remainingBonds Quantity of bonds remaining in the position after a partial withdraw * @return bondsMaturity Maturity of the position's remaining bonds * @return bondsIssuanceIndex Borrow period the deposit was made in **/ function position(uint128 tokenId) external view returns ( bytes32 poolHash, uint128 adjustedBalance, uint128 rate, address underlyingToken, uint128 remainingBonds, uint128 bondsMaturity, uint128 bondsIssuanceIndex ); /** * @notice Returns the balance on yield provider and the quantity of bond held * @param tokenId The tokenId of the position * @return bondsQuantity Quantity of bond held, represents funds borrowed * @return normalizedDepositedAmount Amount of deposit placed on yield provider **/ function getPositionRepartition(uint128 tokenId) external view returns (uint128 bondsQuantity, uint128 normalizedDepositedAmount); /** * @notice Deposits tokens into the yield provider and places a bid at the indicated rate within the * respective borrower's order book. A new position is created within the positions map that keeps * track of this position's composition. An ERC721 NFT is minted for the user as a representation * of the position. * @param to The address for which the position is created * @param amount The amount of tokens to be deposited * @param rate The rate at which to bid for a bonds * @param poolHash The identifier of the pool * @param underlyingToken The contract address of the token to be deposited **/ function deposit( address to, uint128 amount, uint128 rate, bytes32 poolHash, address underlyingToken ) external returns (uint128 tokenId); /** * @notice Allows a user to update the rate at which to bid for bonds. A rate is only * upgradable as long as the full amount of deposits are currently allocated with the * yield provider i.e the position does not hold any bonds. * @param tokenId The tokenId of the position * @param newRate The new rate at which to bid for bonds **/ function updateRate(uint128 tokenId, uint128 newRate) external; /** * @notice Withdraws the amount of tokens that are deposited with the yield provider. * The bonds portion of the position is not affected. * @param tokenId The tokenId of the position **/ function withdraw(uint128 tokenId) external; /** * @notice Set the address of the position descriptor. * Only accessible to governance. * @param positionDescriptor The address of the position descriptor **/ function setPositionDescriptor(address positionDescriptor) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; library Errors { // *** Contract Specific Errors *** // BorrowerPools error BP_BORROW_MAX_BORROWABLE_AMOUNT_EXCEEDED(); // "Amount borrowed is too big, exceeding borrowable capacity"; error BP_REPAY_NO_ACTIVE_LOAN(); // "No active loan to be repaid, action cannot be performed"; error BP_BORROW_UNSUFFICIENT_BORROWABLE_AMOUNT_WITHIN_BRACKETS(); // "Amount provided is greater than available amount within min rate and max rate brackets"; error BP_REPAY_AT_MATURITY_ONLY(); // "Maturity has not been reached yet, action cannot be performed"; error BP_BORROW_COOLDOWN_PERIOD_NOT_OVER(); // "Cooldown period after a repayment is not over"; error BP_MULTIPLE_BORROW_AFTER_MATURITY(); // "Cannot borrow again from pool after loan maturity"; error BP_POOL_NOT_ACTIVE(); // "Pool not active" error BP_POOL_DEFAULTED(); // "Pool defaulted" error BP_LOAN_ONGOING(); // "There's a loan ongoing, cannot update rate" error BP_BORROW_OUT_OF_BOUND_AMOUNT(); // "Amount provided is greater than available amount, action cannot be performed"; error BP_POOL_CLOSED(); // "Pool closed"; error BP_OUT_OF_BOUND_MIN_RATE(); // "Rate provided is lower than minimum rate of the pool"; error BP_OUT_OF_BOUND_MAX_RATE(); // "Rate provided is greater than maximum rate of the pool"; error BP_UNMATCHED_TOKEN(); // "Token/Asset provided does not match the underlying token of the pool"; error BP_RATE_SPACING(); // "Decimals of rate provided do not comply with rate spacing of the pool"; error BP_BOND_ISSUANCE_ID_TOO_HIGH(); // "Bond issuance id is too high"; error BP_NO_DEPOSIT_TO_WITHDRAW(); // "Deposited amount non-borrowed equals to zero"; error BP_TARGET_BOND_ISSUANCE_INDEX_EMPTY(); // "Target bond issuance index has no amount to withdraw"; error BP_EARLY_REPAY_NOT_ACTIVATED(); // "The early repay feature is not activated for this pool"; // PoolController error PC_POOL_NOT_ACTIVE(); // "Pool not active" error PC_POOL_DEFAULTED(); // "Pool defaulted" error PC_POOL_ALREADY_SET_FOR_BORROWER(); // "Targeted borrower is already set for another pool"; error PC_POOL_TOKEN_NOT_SUPPORTED(); // "Underlying token is not supported by the yield provider"; error PC_DISALLOW_UNMATCHED_BORROWER(); // "Revoking the wrong borrower as the provided borrower does not match the provided address"; error PC_RATE_SPACING_COMPLIANCE(); // "Provided rate must be compliant with rate spacing"; error PC_NO_ONGOING_LOAN(); // "Cannot default a pool that has no ongoing loan"; error PC_NOT_ENOUGH_PROTOCOL_FEES(); // "Not enough registered protocol fees to withdraw"; error PC_POOL_ALREADY_CLOSED(); // "Pool already closed"; error PC_ZERO_POOL(); // "Cannot make actions on the zero pool"; error PC_ZERO_ADDRESS(); // "Cannot make actions on the zero address"; error PC_REPAYMENT_PERIOD_ONGOING(); // "Cannot default pool while repayment period in ongoing" error PC_ESTABLISHMENT_FEES_TOO_HIGH(); // "Cannot set establishment fee over 100% of loan amount" error PC_BORROWER_ALREADY_AUTHORIZED(); // "Borrower already authorized on another pool" // PositionManager error POS_MGMT_ONLY_OWNER(); // "Only the owner of the position token can manage it (update rate, withdraw)"; error POS_POSITION_ONLY_IN_BONDS(); // "Cannot withdraw a position that's only in bonds"; error POS_ZERO_AMOUNT(); // "Cannot deposit zero amount"; error POS_TIMELOCK(); // "Cannot withdraw or update rate in the same block as deposit"; error POS_POSITION_DOES_NOT_EXIST(); // "Position does not exist"; error POS_POOL_DEFAULTED(); // "Pool defaulted"; error POS_ZERO_ADDRESS(); // "Cannot make actions on the zero address"; error POS_NOT_ALLOWED(); // "Transaction sender is not allowed to perform the target action"; // PositionDescriptor error POD_BAD_INPUT(); // "Input pool identifier does not correspond to input pool hash"; //*** Library Specific Errors *** // WadRayMath error MATH_MULTIPLICATION_OVERFLOW(); // "The multiplication would result in a overflow"; error MATH_ADDITION_OVERFLOW(); // "The addition would result in a overflow"; error MATH_DIVISION_BY_ZERO(); // "The division would result in a divzion by zero"; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../extensions/AaveILendingPool.sol"; library Types { struct PositionDetails { uint128 adjustedBalance; uint128 rate; bytes32 poolHash; address underlyingToken; uint128 bondsIssuanceIndex; uint128 remainingBonds; uint128 bondsMaturity; uint128 creationTimestamp; } struct Tick { mapping(uint128 => uint128) bondsIssuanceIndexMultiplier; uint128 bondsQuantity; uint128 adjustedTotalAmount; uint128 adjustedRemainingAmount; uint128 adjustedWithdrawnAmount; uint128 adjustedPendingAmount; uint128 normalizedLoanedAmount; uint128 lastFeeDistributionTimestamp; uint128 atlendisLiquidityRatio; uint128 yieldProviderLiquidityRatio; uint128 accruedFees; } struct PoolParameters { bytes32 POOL_HASH; address UNDERLYING_TOKEN; uint8 TOKEN_DECIMALS; ILendingPool YIELD_PROVIDER; uint128 MIN_RATE; uint128 MAX_RATE; uint128 RATE_SPACING; uint128 MAX_BORROWABLE_AMOUNT; uint128 LOAN_DURATION; uint128 LIQUIDITY_REWARDS_DISTRIBUTION_RATE; uint128 COOLDOWN_PERIOD; uint128 REPAYMENT_PERIOD; uint128 LATE_REPAY_FEE_PER_BOND_RATE; uint128 ESTABLISHMENT_FEE_RATE; uint128 REPAYMENT_FEE_RATE; uint128 LIQUIDITY_REWARDS_ACTIVATION_THRESHOLD; bool EARLY_REPAY; } struct PoolState { bool active; bool defaulted; bool closed; uint128 currentMaturity; uint128 bondsIssuedQuantity; uint128 normalizedBorrowedAmount; uint128 normalizedAvailableDeposits; uint128 lowerInterestRate; uint128 nextLoanMinStart; uint128 remainingAdjustedLiquidityRewardsReserve; uint128 yieldProviderLiquidityRatio; uint128 currentBondsIssuanceIndex; uint128 defaultTimestamp; } struct Pool { PoolParameters parameters; PoolState state; mapping(uint256 => Tick) ticks; } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"POD_BAD_INPUT","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"poolIdentifier","type":"string"},{"indexed":false,"internalType":"bytes32","name":"poolHash","type":"bytes32"}],"name":"SetPoolIdentifier","type":"event"},{"inputs":[{"internalType":"bytes32","name":"poolHash","type":"bytes32"}],"name":"getPoolIdentifier","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"poolIdentifier","type":"string"},{"internalType":"bytes32","name":"poolHash","type":"bytes32"}],"name":"setPoolIdentifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPositionManager","name":"position","type":"address"},{"internalType":"uint128","name":"tokenId","type":"uint128"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614a7f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806322393217146100465780638c00e9761461006f5780639251796c14610084575b600080fd5b61005961005436600461231f565b610097565b6040516100669190612368565b60405180910390f35b61008261007d36600461239b565b610139565b005b610059610092366004612440565b6101db565b60008181526020819052604090208054606091906100b490612479565b80601f01602080910402602001604051908101604052809291908181526020018280546100e090612479565b801561012d5780601f106101025761010080835404028352916020019161012d565b820191906000526020600020905b81548152906001019060200180831161011057829003601f168201915b50505050509050919050565b80838360405160200161014d9291906124dd565b604051602081830303815290604052805190602001201461018157604051631370d24960e31b815260040160405180910390fd5b600081815260208190526040902061019a908484612286565b507fbfd66bf4d5f0bf623f832209b1954a49f6cd3926f1d3cb38b67311d6dec4ad8b8383836040516101ce939291906124f9565b60405180910390a1505050565b604051633103751960e11b81526001600160801b0382166004820152606090600090819081906001600160a01b03871690636206ea329060240160e06040518083038186803b15801561022d57600080fd5b505afa158015610241573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610265919061251d565b505060405163d89f46ab60e01b81526001600160801b038b16600482015294975091955093506000928392506001600160a01b038a16915063d89f46ab90602401604080518083038186803b1580156102bd57600080fd5b505afa1580156102d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f591906125af565b915091506000836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561033457600080fd5b505afa158015610348573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261037091908101906125f4565b905060006103c461037f610420565b610387610b71565b61038f610b9d565b61039d8d8c888d8b8d6114a2565b6040516020016103b094939291906126bd565b6040516020818303038152906040526114f8565b90506103f26103d28a61165e565b6000898152602081815260409182902091516103b0939291869101612843565b6040516020016104029190612acf565b60405160208183030381529060405297505050505050505092915050565b6060604051602001610b5d907f3c7374796c6520747970653d22746578742f637373223e2e7374317b66696c6c81527f3a6e6f6e653b7374726f6b653a233737373138383b7374726f6b652d7769647460208201527f683a302e353b7374726f6b652d6d697465726c696d69743a31303b7d2e73743260408201527f7b66696c6c3a233737373138383b7d2e7374337b66696c6c3a2346464646464660608201527f3b7d2e7374347b66696c6c3a234643423445303b7d2e7374357b666f6e742d6660808201527f616d696c793a27526f626f746f2d626f6c64273b666f6e742d73697a653a313660a08201527f70783b7d3c2f7374796c653e3c72616469616c4772616469656e742069643d2260c08201527f53564749445f315f222063783d223235332e34383834222063793d223431372e60e08201527f343238342220723d223337332e3231393122206772616469656e745472616e736101008201527f666f726d3d226d617472697828302e383938362030203020302e3836333320336101208201527f382e3230332031362e383935332922206772616469656e74556e6974733d22756101408201527f73657253706163654f6e557365223e3c73746f7020206f66667365743d2230226101608201527f207374796c653d2273746f702d636f6c6f723a23334130303346222f3e3c73746101808201527f6f7020206f66667365743d223122207374796c653d2273746f702d636f6c6f726101a08201527f3a23304130303241222f3e3c2f72616469616c4772616469656e743e3c7061746101c08201527f68207374796c653d2266696c6c3a75726c282353564749445f315f293b7374726101e08201527f6f6b653a234646464646463b7374726f6b652d77696474683a302e343430343b6102008201527f7374726f6b652d6d697465726c696d69743a31303b2220643d224d302c3734396102208201527f2e3956342e3643302c322e312c322e312c302c342e362c30683532322e3863326102408201527f2e352c302c342e362c322e312c342e362c342e36763734352e3363302c322e356102608201527f2d322e312c342e362d342e362c342e3648342e3643322e312c3735342e352c306102808201527f2c3735322e342c302c3734392e397a222f3e3c7265637420783d2232372e33226102a08201527f20793d2236312e342220636c6173733d22737431222077696474683d223437376102c08201527f2e3822206865696768743d223537322e39222f3e3c6c696e6520636c6173733d6102e08201527f22737431222078313d2232372e33222079313d223533382e37222078323d22356103008201527f30352e31222079323d223533382e37222f3e3c6c696e6520636c6173733d22736103208201527f7431222078313d2232372e33222079313d223434332e36222078323d223530356103408201527f2e31222079323d223434332e36222f3e3c6c696e6520636c6173733d227374316103608201527f222078313d2232372e33222079313d223334382e31222078323d223530352e316103808201527f222079323d223334382e31222f3e3c6c696e6520636c6173733d2273743122206103a08201527f78313d2232372e33222079313d223235322e35222078323d223530352e3122206103c08201527f79323d223235322e35222f3e3c6c696e6520636c6173733d22737431222078316103e08201527f3d2232372e33222079313d22313537222078323d223530352e31222079323d226104008201527f313537222f3e3c6c696e6520636c6173733d22737431222078313d223132322e6104208201527f38222079313d2236312e34222078323d223132322e38222079323d223633342e6104408201527f33222f3e3c6c696e6520636c6173733d22737431222078313d223231382e34226104608201527f2079313d2236312e34222078323d223231382e34222079323d223633342e33226104808201527f2f3e3c6c696e6520636c6173733d22737431222078313d22333134222079313d6104a08201527f2236312e34222078323d22333134222079323d223633342e33222f3e3c6c696e6104c08201527f6520636c6173733d22737431222078313d223430392e35222079313d2236312e6104e08201527f34222078323d223430392e35222079323d223633342e33222f3e3c636972636c6105008201527f6520636c6173733d22737432222063783d223430392e35222063793d223135376105208201527f2220723d22352e34222f3e3c636972636c6520636c6173733d227374322220636105408201527f783d223530352e31222063793d223334372e382220723d22352e34222f3e3c636105608201527f6972636c6520636c6173733d22737432222063783d2232372e33222063793d226105808201527f3533382e372220723d22352e34222f3e3c636972636c6520636c6173733d22736105a08201527f7432222063783d2232372e33222063793d223135362e342220723d22352e34226105c082015261179f60f11b6105e08201526105e20190565b604051602081830303815290604052905090565b6060610b7b611794565b610b836117a5565b610b8b6120a0565b604051602001610b5d93929190612b14565b6060604051602001610b5d907f3c7061746820636c6173733d227374332220643d224d3337382e322c33302e3581527f6c352e342c31392e31682d322e336c2d302e382d332e31483337366c2d302e3860208201527f2c332e31682d322e334c3337382e322c33302e357a204d3338302c34342e356c60408201527f2d312e322d342e386c2d302e352d322e326c2d302e352c322e326c2d312e332c60608201527f342e38483338307a222f3e3c7061746820636c6173733d227374332220643d2260808201527f4d3339352e322c33332e31682d322e39563331683876322e31682d322e39763160a08201527f362e35682d322e325633332e317a222f3e3c7061746820636c6173733d22737460c08201527f332220643d224d3431302e362c333168322e327631362e3568342e387632682d60e08201527f375633317a222f3e3c7061746820636c6173733d227374332220643d224d34326101008201527f372e352c333168362e3276322e31682d342e3176372e3168332e3576322e31686101208201527f2d332e3576352e3368342e3176322e31682d362e325633317a222f3e3c7061746101408201527f6820636c6173733d227374332220643d224d3434342e362c33302e336c352e386101608201527f2c392e376c312e332c322e336c2d302e312d322e3256333168322e327631396c6101808201527f2d352e392d392e376c2d312e332d326c302e312c3276392e33682d322e3256336101a08201527f302e337a222f3e3c7061746820636c6173733d227374332220643d224d3436356101c08201527f2e332c33302e3863312e332c302e312c322e342c302e332c332e352c302e38636101e08201527f312c302e352c312e392c312e312c322e372c312e3963302e372c302e382c312e6102008201527f332c312e382c312e372c322e3963302e342c312e312c302e362c322e342c302e6102208201527f362c332e3963302c312e342d302e322c322e372d302e362c332e39632d302e346102408201527f2c312e312d312c322e312d312e372c322e39632d302e372c302e382d312e362c6102608201527f312e342d322e372c312e39632d312c302e352d322e322c302e372d332e352c306102808201527f2e385633302e387a204d3436372e352c34372e3363302e352d302e322c312d306102a08201527f2e342c312e352d302e3763302e352d302e332c302e392d302e382c312e332d316102c08201527f2e3463302e342d302e362c302e372d312e322c302e392d3263302e322d302e386102e08201527f2c302e342d312e382c302e342d322e3863302d312e312d302e312d322d302e346103008201527f2d322e38632d302e322d302e382d302e352d312e352d302e392d32632d302e346103208201527f2d302e362d302e382d312d312e332d312e34632d302e352d302e332d312d302e6103408201527f362d312e352d302e375634372e337a222f3e3c7061746820636c6173733d22736103608201527f74332220643d224d3438342e342c333168322e327631382e36682d322e3256336103808201527f317a222f3e3c7061746820636c6173733d227374332220643d224d3439382c346103a08201527f362e3863302e342c302e322c302e382c302e342c312e322c302e3663302e342c6103c08201527f302e322c302e392c302e332c312e342c302e3363302e332c302c302e362c302c6103e08201527f302e392d302e3173302e352d302e322c302e372d302e3463302e322d302e322c6104008201527f302e342d302e342c302e352d302e3763302e312d302e332c302e322d302e362c6104208201527f302e322d3163302d302e332c302d302e352d302e312d302e38632d302e312d306104408201527f2e332d302e322d302e362d302e332d302e39632d302e322d302e332d302e332d6104608201527f302e372d302e362d31632d302e322d302e342d302e352d302e382d302e392d316104808201527f2e326c2d312e352d312e39632d302e342d302e352d302e372d302e392d312d316104a08201527f2e34632d302e332d302e342d302e352d302e382d302e362d312e32632d302e326104c08201527f2d302e342d302e332d302e382d302e342d312e31632d302e312d302e342d302e6104e08201527f312d302e372d302e312d312e3163302d302e362c302e312d312e312c302e332d6105008201527f312e3663302e322d302e352c302e352d302e392c302e382d312e3363302e342d6105208201527f302e342c302e382d302e362c312e332d302e3863302e352d302e322c312e312d6105408201527f302e332c312e372d302e3363302e352c302c312c302e312c312e362c302e32636105608201527f302e352c302e312c312c302e342c312e352c302e366c2d302e392c312e38632d6105808201527f302e332d302e322d302e362d302e332d302e392d302e34632d302e332d302e316105a08201527f2d302e372d302e322d312d302e32632d302e362c302d312e312c302e322d312e6105c08201527f352c302e35632d302e342c302e342d302e362c302e392d302e362c312e3563306105e08201527f2c302e322c302c302e342c302e312c302e3663302c302e322c302e312c302e346106008201527f2c302e322c302e3663302e312c302e322c302e322c302e352c302e342c302e376106208201527f63302e322c302e332c302e342c302e362c302e362c302e396c322e322c322e396106408201527f63302e332c302e342c302e352c302e372c302e382c312e3163302e322c302e346106608201527f2c302e352c302e372c302e362c312e3163302e322c302e342c302e332c302e386106808201527f2c302e342c312e3263302e312c302e342c302e322c302e382c302e322c312e336106a08201527f63302c302e372d302e312c312e332d302e332c312e39632d302e322c302e362d6106c08201527f302e352c312d302e392c312e34632d302e342c302e342d302e392c302e372d316106e08201527f2e342c302e39632d302e362c302e322d312e322c302e332d312e382c302e33636107008201527f2d302e372c302d312e332d302e312d322d302e33632d302e362d302e322d312e6107208201527f322d302e352d312e362d302e384c3439382c34362e387a222f3e00000000000061074082015261075a0190565b60606114ad876120b1565b6114b6876120e2565b6114bf866121a8565b6114ca88878761220c565b6040516020016114dd9493929190612b57565b60405160208183030381529060405290509695505050505050565b606081516000141561151857505060408051602081019091526000815290565b6000604051806060016040528060408152602001614a0a60409139905060006003845160026115479190612bc4565b6115519190612bf2565b61155c906004612c06565b9050600061156b826020612bc4565b67ffffffffffffffff811115611583576115836125de565b6040519080825280601f01601f1916602001820160405280156115ad576020820181803683370190505b509050818152600183018586518101602084015b81831015611619576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f81168501518253506001016115c1565b600389510660018114611633576002811461164457611650565b613d3d60f01b600119830152611650565b603d60f81b6000198301525b509398975050505050505050565b60606001600160801b03821661168b5750506040805180820190915260018152600360fc1b602082015290565b8160005b6001600160801b038216156116be57806116a881612c25565b91506116b79050600a83612c4c565b915061168f565b6000816001600160801b031667ffffffffffffffff8111156116e2576116e26125de565b6040519080825280601f01601f19166020018201604052801561170c576020820181803683370190505b508593509050815b6001600160801b0384161561178b5761172e600a85612c72565b611739906030612c98565b60f81b8261174683612cc3565b9250826001600160801b03168151811061176257611762612ce6565b60200101906001600160f81b031916908160001a905350611784600a85612c4c565b9350611714565b50949350505050565b6060604051602001610b5d90612cfc565b6060604051602001610b5d907f3c636972636c65207374796c653d2266696c6c3a23303030304646222063783d81527f22313134222063793d223332302220723d223338222f3e3c6c696e656172477260208201527f616469656e742069643d223722206772616469656e74556e6974733d2275736560408201527f7253706163654f6e557365222078313d223237392e38303038222079313d223160608201527f3230332e303338222078323d223537382e39313239222079323d22313230332e60808201527f30333822206772616469656e745472616e73666f726d3d226d6174726978283060a08201527f2031202d31203020313434342e34303532202d35342e3434363229223e3c737460c08201527f6f7020206f66667365743d223022207374796c653d2273746f702d636f6c6f7260e08201527f3a23464142324445222f3e3c73746f7020206f66667365743d223122207374796101008201527f6c653d2273746f702d636f6c6f723a23303030304646222f3e3c2f6c696e65616101208201527f724772616469656e743e3c636972636c65207374796c653d2266696c6c3a75726101408201527f6c282337293b222063783d223234312e34222063793d223337342e392220723d6101608201527f223134392e36222f3e3c6c696e6561724772616469656e742069643d223822206101808201527f6772616469656e74556e6974733d227573657253706163654f6e5573652220786101a08201527f313d223230322e39353031222079313d223339302e34323039222078323d22316101c08201527f30392e36333533222079323d223438332e37333537223e3c73746f7020206f666101e08201527f667365743d223022207374796c653d2273746f702d636f6c6f723a23304230346102008201527f3433222f3e3c73746f7020206f66667365743d22302e3531373322207374796c6102208201527f653d2273746f702d636f6c6f723a23314231343634222f3e3c73746f7020206f6102408201527f66667365743d223122207374796c653d2273746f702d636f6c6f723a233245336102608201527f313930222f3e3c2f6c696e6561724772616469656e743e3c70617468207374796102808201527f6c653d2266696c6c3a75726c282338293b2220643d224d3230372e382c3339396102a08201527f2e366332372e372c34312e382c33312e352c38382c382e362c3130332e32632d6102c08201527f32332c31352e322d36342d362e332d39312e372d34382e31732d33312e352d386102e08201527f382d382e362d3130332e32433133392c3333362e332c3138302e312c3335372e6103008201527f392c3230372e382c3339392e367a222f3e3c6c696e6561724772616469656e746103208201527f2069643d223922206772616469656e74556e6974733d227573657253706163656103408201527f4f6e557365222078313d223730352e38393035222079313d223834312e3932326103608201527f33222078323d223739372e34393035222079323d223834312e393232332220676103808201527f72616469656e745472616e73666f726d3d226d6174726978282d302e373037316103a08201527f20302e37303731202d302e37303731202d302e3730373120313236332e3134396103c08201527f35203532322e3832303629223e3c73746f7020206f66667365743d22302e32316103e08201527f363522207374796c653d2273746f702d636f6c6f723a23464142324445222f3e6104008201527f3c73746f7020206f66667365743d223122207374796c653d2273746f702d636f6104208201527f6c6f723a23303046464646222f3e3c2f6c696e6561724772616469656e743e3c6104408201527f636972636c65207374796c653d2266696c6c3a75726c282339293b222063783d6104608201527f223133362e33222063793d223435392220723d2234352e38222f3e3c6c696e656104808201527f61724772616469656e742069643d22313022206772616469656e74556e6974736104a08201527f3d227573657253706163654f6e557365222078313d22313538392e39373738226104c08201527f2079313d223831372e3737222078323d22313630352e33343835222079323d226104e08201527f3836302e3534303522206772616469656e745472616e73666f726d3d226d61746105008201527f726978282d302e39383332202d302e3138323520302e31383235202d302e39386105208201527f333220313739392e3832353120313437312e3032333129223e3c73746f7020206105408201527f6f66667365743d223022207374796c653d2273746f702d636f6c6f723a2330426105608201527f30343433222f3e3c73746f7020206f66667365743d22302e35313733222073746105808201527f796c653d2273746f702d636f6c6f723a23314231343634222f3e3c73746f70206105a08201527f206f66667365743d223122207374796c653d2273746f702d636f6c6f723a23326105c08201527f4533313930222f3e3c2f6c696e6561724772616469656e743e3c636972636c656105e08201527f207374796c653d2266696c6c3a75726c28233130293b222063783d223338312e6106008201527f34222063793d223334392e382220723d2232322e31222f3e3c6c696e656172476106208201527f72616469656e742069643d22313122206772616469656e74556e6974733d22756106408201527f73657253706163654f6e557365222078313d223232352e36393634222079313d6106608201527f223230312e30373339222078323d223232372e34393334222079323d223237326106808201527f2e30353439223e3c73746f7020206f66667365743d223022207374796c653d226106a08201527f73746f702d636f6c6f723a23464336454330222f3e3c73746f7020206f6666736106c08201527f65743d223122207374796c653d2273746f702d636f6c6f723a233943303035446106e08201527f222f3e3c2f6c696e6561724772616469656e743e3c636972636c65207374796c6107008201527f653d2266696c6c3a75726c28233131293b222063783d223232362e3722206379610720820152721e91191a18171c1110391e91199a171b91179f60691b6107408201526107530190565b6060604051602001610b5d90613834565b60606120bc8261165e565b6040516020016120cc919061422c565b6040516020818303038152906040529050919050565b60008181526020819052604081208054606092919061210090612479565b80601f016020809104026020016040519081016040528092919081815260200182805461212c90612479565b80156121795780601f1061214e57610100808354040283529160200191612179565b820191906000526020600020905b81548152906001019060200180831161215c57829003601f168201915b5050505050905080604051602001612191919061447f565b604051602081830303815290604052915050919050565b6060662386f26fc10000655af3107a40006121cb6121c68386612c4c565b61165e565b6121e3826121d98588612c72565b6121c69190612c4c565b6040516020016121f49291906145c5565b60405160208183030381529060405292505050919050565b6060670de0b6b3a7640000662386f26fc1000061222c6121c68387612c4c565b61223a826121d98589612c72565b876122486121c68689612c4c565b612256856121d9888b612c72565b8a60405160200161226c9695949392919061473e565b604051602081830303815290604052925050509392505050565b82805461229290612479565b90600052602060002090601f0160209004810192826122b457600085556122fa565b82601f106122cd5782800160ff198235161785556122fa565b828001600101855582156122fa579182015b828111156122fa5782358255916020019190600101906122df565b5061230692915061230a565b5090565b5b80821115612306576000815560010161230b565b60006020828403121561233157600080fd5b5035919050565b60005b8381101561235357818101518382015260200161233b565b83811115612362576000848401525b50505050565b6020815260008251806020840152612387816040850160208701612338565b601f01601f19169190910160400192915050565b6000806000604084860312156123b057600080fd5b833567ffffffffffffffff808211156123c857600080fd5b818601915086601f8301126123dc57600080fd5b8135818111156123eb57600080fd5b8760208285010111156123fd57600080fd5b6020928301989097509590910135949350505050565b6001600160a01b038116811461242857600080fd5b50565b6001600160801b038116811461242857600080fd5b6000806040838503121561245357600080fd5b823561245e81612413565b9150602083013561246e8161242b565b809150509250929050565b600181811c9082168061248d57607f821691505b602082108114156124ae57634e487b7160e01b600052602260045260246000fd5b50919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260006124f16020830184866124b4565b949350505050565b60408152600061250d6040830185876124b4565b9050826020830152949350505050565b600080600080600080600060e0888a03121561253857600080fd5b87519650602088015161254a8161242b565b604089015190965061255b8161242b565b606089015190955061256c81612413565b608089015190945061257d8161242b565b60a089015190935061258e8161242b565b60c089015190925061259f8161242b565b8091505092959891949750929550565b600080604083850312156125c257600080fd5b82516125cd8161242b565b602084015190925061246e8161242b565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561260657600080fd5b815167ffffffffffffffff8082111561261e57600080fd5b818401915084601f83011261263257600080fd5b815181811115612644576126446125de565b604051601f8201601f19908116603f0116810190838211818310171561266c5761266c6125de565b8160405282815287602084870101111561268557600080fd5b612696836020830160208801612338565b979650505050505050565b600081516126b3818560208601612338565b9290920192915050565b7f3c7376672076657273696f6e3d22312e31222069643d224c617965725f31222081527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660208201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260408201527f672f313939392f786c696e6b2220783d223070782220793d223070782220766960608201527f6577426f783d2230203020353332203735342e3522207374796c653d22656e6160808201527f626c652d6261636b67726f756e643a6e65772030203020353332203735342e3560a08201527f3b2220786d6c3a73706163653d227072657365727665223e000000000000000060c0820152600085516127d98160d8850160208a01612338565b8551908301906127f08160d8840160208a01612338565b85519101906128068160d8840160208901612338565b845191019061281c8160d8840160208801612338565b61283760d882840101651e17b9bb339f60d11b815260060190565b98975050505050505050565b727b226e616d65223a22506f736974696f6e202360681b8152835160009060206128738260138601838a01612338565b7f222c226465736372697074696f6e223a224120506f736974696f6e206f6e20746013928501928301527f68652041746c656e6469732070726f746f636f6c20666f7220706f6f6c20000060338301528554605190600090600181811c90808316806128e057607f831692505b8683108114156128fe57634e487b7160e01b85526022600452602485fd5b808015612912576001811461292757612958565b60ff1985168988015283890187019550612958565b60008d81526020902060005b8581101561294e5781548b82018a0152908401908901612933565b505086848a010195505b50507f2e2054686973204e465420726570726573656e747320796f7572207368617265845250507f206f662074686520706f6f6c2c20697473207468656f7269746963616c2070726020830152507f69636520646570656e6473206f6e2074686520737461747573206f662074686560408201527f20706f6f6c2c202074686520616d6f756e74206f6620746f6b656e7320796f7560608201527f206f726967696e616c6c79206465706f736974656420616e642074686520646960808201527f66666572656e74207265776172647320616c6c6f636174656420746f2069742e60a08201527f2265787465726e616c5f75726c223a2268747470733a2f2f6170702e61746c6560c08201527f6e6469732e696f2f222c22696d616765223a2022646174613a696d6167652f7360e08201526d1d99cade1b5b0ed8985cd94d8d0b60921b610100820152612ac2612ab461010e83015b896126a1565b61227d60f01b815260020190565b9998505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612b0781601d850160208701612338565b91909101601d0192915050565b60008451612b26818460208901612338565b845190830190612b3a818360208901612338565b8451910190612b4d818360208801612338565b0195945050505050565b60008551612b69818460208a01612338565b855190830190612b7d818360208a01612338565b8551910190612b90818360208901612338565b8451910190612ba3818360208801612338565b019695505050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612bd757612bd7612bae565b500190565b634e487b7160e01b600052601260045260246000fd5b600082612c0157612c01612bdc565b500490565b6000816000190483118215151615612c2057612c20612bae565b500290565b60006001600160801b0380831681811415612c4257612c42612bae565b6001019392505050565b60006001600160801b0380841680612c6657612c66612bdc565b92169190910492915050565b60006001600160801b0380841680612c8c57612c8c612bdc565b92169190910692915050565b60006001600160801b03808316818516808303821115612cba57612cba612bae565b01949350505050565b60006001600160801b03821680612cdc57612cdc612bae565b6000190192915050565b634e487b7160e01b600052603260045260246000fd5b7f3c6c696e6561724772616469656e742069643d223122206772616469656e745581527f6e6974733d227573657253706163654f6e557365222078313d223530322e383660208201527f3634222079313d223438352e36303537222078323d223538372e38303139222060408201527f79323d223438352e3630353722206772616469656e745472616e73666f726d3d60608201527f226d6174726978282d302e37303936202d302e3730343620302e37303436202d60808201527f302e37303936203134372e39313939203835382e3139323129223e3c73746f7060a08201527f20206f66667365743d223022207374796c653d2273746f702d636f6c6f723a2360c082018190527f464142324445222f3e3c73746f7020206f66667365743d223122207374796c6560e08301527f3d2273746f702d636f6c6f723a23303030304646222f3e3c2f6c696e656172476101008301527f72616469656e743e3c636972636c65207374796c653d2266696c6c3a75726c286101208301527f2331293b222063783d223130332e31222063793d223132392e342220723d22346101408301527f322e35222f3e3c6c696e6561724772616469656e742069643d223222206772616101608301527f6469656e74556e6974733d227573657253706163654f6e557365222078313d226101808301527f343835332e383335222079313d223938342e35383333222078323d22343835346101a08301527f2e38323138222079323d22313032332e3535383822206772616469656e7454726101c08301527f616e73666f726d3d226d6174726978282d302e39373732202d302e32313233206101e08301527f302e32313233202d302e3937373220343636372e3036303520323232382e31356102008301527f353329223e3c73746f7020206f66667365743d223022207374796c653d2273746102208301527f6f702d636f6c6f723a23303046464646222f3e3c73746f7020206f66667365746102408301527f3d223122207374796c653d2273746f702d636f6c6f723a23464646463030222f6102608301527f3e3c2f6c696e6561724772616469656e743e3c636972636c65207374796c653d6102808301527f2266696c6c3a75726c282332293b222063783d223133362e37222063793d22326102a08301527f31352e332220723d223139222f3e3c6c696e6561724772616469656e742069646102c08301527f3d223322206772616469656e74556e6974733d227573657253706163654f6e556102e08301527f7365222078313d223639372e31303838222079313d223638352e3632353722206103008301527f78323d223738342e36383237222079323d223638352e363235372220677261646103208301527f69656e745472616e73666f726d3d226d6174726978282d322e3034323620302e6103408301527f36373637202d302e37343331202d302e3833353320323237322e3033313220326103608301527f36342e3638343429223e3c73746f70206f66667365743d223022207374796c656103808301527f3d2273746f702d636f6c6f723a23303046464646222f3e3c73746f7020206f666103a08301527f667365743d223122207374796c653d2273746f702d636f6c6f723a23394446436103c08301527f3932222f3e3c2f6c696e6561724772616469656e743e3c6c696e65207374796c6103e08301527f653d2266696c6c3a6e6f6e653b7374726f6b653a75726c282333293b7374726f6104008301527f6b652d77696474683a342e3134323b7374726f6b652d6c696e656361703a726f6104208301527f756e643b7374726f6b652d6c696e656a6f696e3a726f756e643b7374726f6b656104408301527f2d6d697465726c696d69743a31303b222078313d223334322e36222079313d226104608301527f3137342e32222078323d223135352e39222079323d223231322e34222f3e3c6c6104808301527f696e6561724772616469656e742069643d223422206772616469656e74556e696104a08301527f74733d227573657253706163654f6e557365222078313d223334382e373632386104c08301527f222079313d223131392e37373634222078323d223335302e38383939222079326104e08301527f3d223230332e37393833223e3c73746f7020206f66667365743d2230222073746105008301527f796c653d2273746f702d636f6c6f723a23303046464646222f3e3c73746f70206105208301527f206f66667365743d223122207374796c653d2273746f702d636f6c6f723a23306105408301527f3030304646222f3e3c2f6c696e6561724772616469656e743e3c636972636c656105608301527f207374796c653d2266696c6c3a75726c282334293b222063783d2233353022206105808301527f63793d223136362e382220723d223431222f3e3c636972636c65207374796c656105a08301527f3d2266696c6c3a234646464630303b222063783d223335342e38222063793d226105c08301527f37302220723d22352e39222f3e3c6c696e6561724772616469656e742069643d6105e08301527f223522206772616469656e74556e6974733d227573657253706163654f6e55736106008301527f65222078313d223134302e37373536222079313d223233302e313132322220786106208301527f323d223232382e39343132222079323d223233302e31313232223e3c73746f706106408301526106608201527f394446433932222f3e3c73746f7020206f66667365743d223122207374796c656106808201527f3d2273746f702d636f6c6f723a23464637424143222f3e3c2f6c696e656172476106a08201527f72616469656e743e3c6c696e65207374796c653d2266696c6c3a6e6f6e653b736106c08201527f74726f6b653a75726c282335293b7374726f6b652d77696474683a342e3733336106e08201527f373b7374726f6b652d6c696e656361703a726f756e643b7374726f6b652d6c696107008201527f6e656a6f696e3a726f756e643b7374726f6b652d6d697465726c696d69743a316107208201527f303b222078313d223134332e31222079313d223231392e32222078323d2232326107408201527f362e36222079323d223234312e31222f3e3c6c696e6561724772616469656e746107608201527f2069643d223622206772616469656e74556e6974733d227573657253706163656107808201527f4f6e557365222078313d223639352e30323834222079313d223831322e3737356107a08201527f35222078323d223738332e37383538222079323d223831322e373735352220676107c08201527f72616469656e745472616e73666f726d3d226d6174726978282d312e313733376107e08201527f20302e39363937202d302e38323434202d302e3634313220313832322e3437346108008201526a101898971b9c9c1b14911f60a91b6108208201527f3c73746f7020206f66667365743d223022207374796c653d2273746f702d636f61082b8201527f6c6f723a23333533444637222f3e3c73746f7020206f66667365743d2231222061084b8201527f7374796c653d2273746f702d636f6c6f723a23464637424143222f3e3c2f6c6961086b8201527f6e6561724772616469656e743e3c6c696e65207374796c653d2266696c6c3a6e61088b8201527f6f6e653b7374726f6b653a75726c282336293b7374726f6b652d77696474683a6108ab8201527f352e333235343b7374726f6b652d6c696e656361703a726f756e643b7374726f6108cb8201527f6b652d6c696e656a6f696e3a726f756e643b7374726f6b652d6d697465726c696108eb8201527f6d69743a31303b222078313d223334322e36222079313d223137342e3222207861090b82015275191e9119191b171b11103c991e91191a18971891179f60511b61092b820152600061094182015b92915050565b7f3c6c696e6561724772616469656e742069643d22313222206772616469656e7481527f556e6974733d227573657253706163654f6e557365222078313d223438342e3160208201527f323733222079313d223239352e35353132222078323d223438352e333939342260408201527f2079323d223334352e3739353922206772616469656e745472616e73666f726d60608201527f3d226d617472697828302e3930343520302e34323636202d302e34323636203060808201527f2e39303435203139332e33333039202d34372e30353529223e3c73746f70202060a08201527f6f66667365743d223022207374796c653d2273746f702d636f6c6f723a23464360c08201527f36454330222f3e3c73746f7020206f66667365743d223122207374796c653d2260e08201527f73746f702d636f6c6f723a23394330303544222f3e3c2f6c696e6561724772616101008201527f6469656e743e3c636972636c65207374796c653d2266696c6c3a75726c2823316101208201527f32293b222063783d223439332e38222063793d223435322e352220723d2232346101408201527f2e35222f3e3c6c696e6561724772616469656e742069643d22313322206772616101608201527f6469656e74556e6974733d227573657253706163654f6e557365222078313d226101808201527f3532382e30383732222079313d223434342e33343034222078323d223532392e6101a08201527f30383934222079323d223438332e3932323722206772616469656e745472616e6101c08201527f73666f726d3d226d617472697828302e3930343520302e34323636202d302e346101e08201527f32363620302e39303435203139332e33333039202d34372e30353529223e3c736102008201527f746f7020206f66667365743d223022207374796c653d2273746f702d636f6c6f6102208201527f723a23303046464646222f3e3c73746f7020206f66667365743d2231222073746102408201527f796c653d2273746f702d636f6c6f723a23303030304646222f3e3c2f6c696e656102608201527f61724772616469656e743e3c636972636c65207374796c653d2266696c6c3a756102808201527f726c28233133293b222063783d223437322e35222063793d223630302e3422206102a08201527f723d2231392e33222f3e3c6c696e6561724772616469656e742069643d2231346102c08201527f22206772616469656e74556e6974733d227573657253706163654f6e557365226102e08201527f2078313d22313031372e34333134222079313d223435332e32363231222078326103008201527f3d22313130362e31383837222079323d223435332e32363231222067726164696103208201527f656e745472616e73666f726d3d226d6174726978282d302e3834393720302e316103408201527f333938202d382e323539333936652d3032202d302e3938373620313336392e366103608201527f353938203839332e3739373929223e3c73746f7020206f66667365743d2230226103808201527f207374796c653d2273746f702d636f6c6f723a23344336464635222f3e3c73746103a08201527f6f7020206f66667365743d22302e3336333422207374796c653d2273746f702d6103c08201527f636f6c6f723a23344134464431222f3e3c73746f7020206f66667365743d22316103e08201527f22207374796c653d2273746f702d636f6c6f723a23343531303841222f3e3c2f6104008201527f6c696e6561724772616469656e743e3c6c696e65207374796c653d2266696c6c6104208201527f3a6e6f6e653b7374726f6b653a75726c28233134293b7374726f6b652d7769646104408201527f74683a352e333235343b7374726f6b652d6c696e656361703a726f756e643b736104608201527f74726f6b652d6c696e656a6f696e3a726f756e643b7374726f6b652d6d6974656104808201527f726c696d69743a31303b222078313d223436362e34222079313d223539392e356104a08201527f222078323d223339332e37222079323d223538392e36222f3e3c6c696e6561726104c08201527f4772616469656e742069643d22313522206772616469656e74556e6974733d226104e08201527f7573657253706163654f6e557365222078313d223534352e34383433222079316105008201527f3d223631372e33353437222078323d223633342e32343136222079323d2236316105208201527f372e3335343722206772616469656e745472616e73666f726d3d226d617472696105408201527f78282d312e3139343320312e35363733202d312e30343832202d302e333136206105608201527f313737382e32303534202d3230392e3538323929223e3c73746f7020206f66666105808201527f7365743d223022207374796c653d2273746f702d636f6c6f723a2341413436386105a08201527f38222f3e3c73746f7020206f66667365743d223122207374796c653d2273746f6105c08201527f702d636f6c6f723a23333533444637222f3e3c2f6c696e6561724772616469656105e08201527f6e743e3c6c696e65207374796c653d2266696c6c3a6e6f6e653b7374726f6b656106008201527f3a75726c28233135293b7374726f6b652d77696474683a352e333235343b73746106208201527f726f6b652d6c696e656361703a726f756e643b7374726f6b652d6c696e656a6f6106408201527f696e3a726f756e643b7374726f6b652d6d697465726c696d69743a31303b22206106608201527f78313d223438372e39222079313d223435372e39222078323d223336352e33226106808201527f2079323d223538312e37222f3e3c6c696e6561724772616469656e742069643d6106a08201527f22313622206772616469656e74556e6974733d227573657253706163654f6e556106c08201527f7365222078313d223432332e35383733222079313d223534392e3331343822206106e08201527f78323d223432342e37313637222079323d223434332e313530322220677261646107008201527f69656e745472616e73666f726d3d226d617472697828302e3930343520302e346107208201527f323636202d302e3432363620302e39303435203139332e33333039202d34372e61074082015265181a9a94911f60d11b6107608201527f3c73746f7020206f66667365743d22392e353935393630652d303222207374796107668201527f6c653d2273746f702d636f6c6f723a23333831303737222f3e3c73746f7020206107868201527f6f66667365743d223122207374796c653d2273746f702d636f6c6f723a2337436107a68201527f31444339222f3e3c2f6c696e6561724772616469656e743e3c636972636c65206107c68201527f7374796c653d2266696c6c3a75726c28233136293b222063783d223336352e386107e68201527f222063793d223538312e362220723d2233392e33222f3e000000000000000000610806820152600061081d820161382e565b7f3c6c696e6561724772616469656e742069643d22313722206772616469656e7481527f556e6974733d227573657253706163654f6e557365222078313d2233382e373160208201527f3732222079313d22322e37343633222078323d223130322e353239222079323d60408201527f2236362e35353831223e3c73746f7020206f66667365743d22302e323136352260608201527f207374796c653d2273746f702d636f6c6f723a23464142324445222f3e3c737460808201527f6f7020206f66667365743d223122207374796c653d2273746f702d636f6c6f7260a08201527f3a23303046464646222f3e3c2f6c696e6561724772616469656e743e3c70617460c08201527f68207374796c653d2266696c6c3a75726c28233137293b2220643d224d31323160e08201527f2e322c35342e314832382e38632d302e392c302d312e372d302e372d312e372d6101008201527f312e375632352e3563302d302e392c302e372d312e372c312e372d312e3768396101208201527f322e3463302e392c302c312e372c302e372c312e372c312e377632362e3943316101408201527f32322e382c35332e342c3132322e312c35342e312c3132312e322c35342e317a6101608201527f222f3e3c74657874207472616e73666f726d3d226d61747269782831203020306101808201527f20312034312e393934332034332e37313036292220636c6173733d22737435226101a08201526401f24a21d160dd1b6101c082015260006144786144656101c58401856126a1565b661e17ba32bc3a1f60c91b815260070190565b9392505050565b7f3c7061746820636c6173733d227374312220643d224d32392e322c3634322e3781527f683335362e3763312e312c302c322e312c312e332c322e312c322e387632342e60208201527f3763302c312e352d312c322e382d322e312c322e384832392e32632d312e312c60408201527f302d322e312d312e332d322e312d322e38762d32342e374332372e312c36343360608201527f2e392c32382c3634322e372c32392e322c3634322e377a222f3e3c746578742060808201527f7472616e73666f726d3d226d617472697828312030203020312033372e35303660a08201527f35203636332e35343237292220636c6173733d2273743320737435223e506f6f60c0820152620361d160ed1b60e0820152600082516145a78160e3850160208701612338565b661e17ba32bc3a1f60c91b60e393909101928301525060ea01919050565b7f3c7061746820636c6173733d227374312220643d224d3339382e312c3634322e81527f38683130342e3563312e312c302c312e392c302e392c312e392c312e3976323660208201527f2e3463302c312e312d302e392c312e392d312e392c312e39483339382e31632d60408201527f312e312c302d312e392d302e392d312e392d312e39762d32362e34433339362e60608201527f322c3634332e372c3339372e312c3634322e382c3339382e312c3634322e387a60808201527f222f3e3c74657874207472616e73666f726d3d226d617472697828312030203060a08201527f2031203432302e33323631203636322e34363739292220636c6173733d22737460c08201526b0199039ba1a911f24972917160a51b60e0820152600083516146f68160ec850160208801612338565b601760f91b60ec9184019182015283516147178160ed840160208801612338565b61473460ed8284010167129e17ba32bc3a1f60c11b815260080190565b9695505050505050565b7f3c7061746820636c6173733d227374312220643d224d3235392e382c3731312e81527f364832392e39632d312e332c302d322e332d312e362d322e332d332e35762d3260208201527f332e3263302d322c312d332e352c322e332d332e35683232392e3963312e332c60408201527f302c322e332c312e362c322e332c332e357632332e32433236322e312c37313060608201527f2c3236312c3731312e362c3235392e382c3731312e367a222f3e3c746578742060808201527f7472616e73666f726d3d226d617472697828312030203020312033382e30333060a08201527f34203730322e31393235292220636c6173733d2273743320737435223e00000060c08201526000875161485a8160dd850160208c01612338565b601760f91b60dd91840191820152875161487b8160de840160208c01612338565b6149fb6149de6149d8612aae6149cb6149c561489c60de888a01018f6126a1565b7f204465706f7369746564203c2f746578743e3c7061746820636c6173733d227381527f74312220643d224d3530312e382c3731312e36483237312e32632d312e332c3060208201527f2d322e332d312e362d322e332d332e35762d32332e3263302d322c312d332e3560408201527f2c322e332d332e35683233302e3763312e332c302c322e332c312e362c322e3360608201527f2c332e357632332e32433530342e312c3731302c3530332e312c3731312e362c60808201527f3530312e382c3731312e367a222f3e3c74657874207472616e73666f726d3d2260a08201527f6d61747269782831203020302031203237382e38393331203730322e3139313960c08201527214911031b630b9b99e9139ba199039ba1a911f60691b60e082015260f30190565b8c6126a1565b601760f91b815260010190565b876126a1565b70102137b93937bbb2b2101e17ba32bc3a1f60791b815260110190565b9a995050505050505050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122041221d56a1c68bedd9835b02245ea1228543a9091a2f8f9d952f5b56a7aae03064736f6c63430008090033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100415760003560e01c806322393217146100465780638c00e9761461006f5780639251796c14610084575b600080fd5b61005961005436600461231f565b610097565b6040516100669190612368565b60405180910390f35b61008261007d36600461239b565b610139565b005b610059610092366004612440565b6101db565b60008181526020819052604090208054606091906100b490612479565b80601f01602080910402602001604051908101604052809291908181526020018280546100e090612479565b801561012d5780601f106101025761010080835404028352916020019161012d565b820191906000526020600020905b81548152906001019060200180831161011057829003601f168201915b50505050509050919050565b80838360405160200161014d9291906124dd565b604051602081830303815290604052805190602001201461018157604051631370d24960e31b815260040160405180910390fd5b600081815260208190526040902061019a908484612286565b507fbfd66bf4d5f0bf623f832209b1954a49f6cd3926f1d3cb38b67311d6dec4ad8b8383836040516101ce939291906124f9565b60405180910390a1505050565b604051633103751960e11b81526001600160801b0382166004820152606090600090819081906001600160a01b03871690636206ea329060240160e06040518083038186803b15801561022d57600080fd5b505afa158015610241573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610265919061251d565b505060405163d89f46ab60e01b81526001600160801b038b16600482015294975091955093506000928392506001600160a01b038a16915063d89f46ab90602401604080518083038186803b1580156102bd57600080fd5b505afa1580156102d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f591906125af565b915091506000836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561033457600080fd5b505afa158015610348573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261037091908101906125f4565b905060006103c461037f610420565b610387610b71565b61038f610b9d565b61039d8d8c888d8b8d6114a2565b6040516020016103b094939291906126bd565b6040516020818303038152906040526114f8565b90506103f26103d28a61165e565b6000898152602081815260409182902091516103b0939291869101612843565b6040516020016104029190612acf565b60405160208183030381529060405297505050505050505092915050565b6060604051602001610b5d907f3c7374796c6520747970653d22746578742f637373223e2e7374317b66696c6c81527f3a6e6f6e653b7374726f6b653a233737373138383b7374726f6b652d7769647460208201527f683a302e353b7374726f6b652d6d697465726c696d69743a31303b7d2e73743260408201527f7b66696c6c3a233737373138383b7d2e7374337b66696c6c3a2346464646464660608201527f3b7d2e7374347b66696c6c3a234643423445303b7d2e7374357b666f6e742d6660808201527f616d696c793a27526f626f746f2d626f6c64273b666f6e742d73697a653a313660a08201527f70783b7d3c2f7374796c653e3c72616469616c4772616469656e742069643d2260c08201527f53564749445f315f222063783d223235332e34383834222063793d223431372e60e08201527f343238342220723d223337332e3231393122206772616469656e745472616e736101008201527f666f726d3d226d617472697828302e383938362030203020302e3836333320336101208201527f382e3230332031362e383935332922206772616469656e74556e6974733d22756101408201527f73657253706163654f6e557365223e3c73746f7020206f66667365743d2230226101608201527f207374796c653d2273746f702d636f6c6f723a23334130303346222f3e3c73746101808201527f6f7020206f66667365743d223122207374796c653d2273746f702d636f6c6f726101a08201527f3a23304130303241222f3e3c2f72616469616c4772616469656e743e3c7061746101c08201527f68207374796c653d2266696c6c3a75726c282353564749445f315f293b7374726101e08201527f6f6b653a234646464646463b7374726f6b652d77696474683a302e343430343b6102008201527f7374726f6b652d6d697465726c696d69743a31303b2220643d224d302c3734396102208201527f2e3956342e3643302c322e312c322e312c302c342e362c30683532322e3863326102408201527f2e352c302c342e362c322e312c342e362c342e36763734352e3363302c322e356102608201527f2d322e312c342e362d342e362c342e3648342e3643322e312c3735342e352c306102808201527f2c3735322e342c302c3734392e397a222f3e3c7265637420783d2232372e33226102a08201527f20793d2236312e342220636c6173733d22737431222077696474683d223437376102c08201527f2e3822206865696768743d223537322e39222f3e3c6c696e6520636c6173733d6102e08201527f22737431222078313d2232372e33222079313d223533382e37222078323d22356103008201527f30352e31222079323d223533382e37222f3e3c6c696e6520636c6173733d22736103208201527f7431222078313d2232372e33222079313d223434332e36222078323d223530356103408201527f2e31222079323d223434332e36222f3e3c6c696e6520636c6173733d227374316103608201527f222078313d2232372e33222079313d223334382e31222078323d223530352e316103808201527f222079323d223334382e31222f3e3c6c696e6520636c6173733d2273743122206103a08201527f78313d2232372e33222079313d223235322e35222078323d223530352e3122206103c08201527f79323d223235322e35222f3e3c6c696e6520636c6173733d22737431222078316103e08201527f3d2232372e33222079313d22313537222078323d223530352e31222079323d226104008201527f313537222f3e3c6c696e6520636c6173733d22737431222078313d223132322e6104208201527f38222079313d2236312e34222078323d223132322e38222079323d223633342e6104408201527f33222f3e3c6c696e6520636c6173733d22737431222078313d223231382e34226104608201527f2079313d2236312e34222078323d223231382e34222079323d223633342e33226104808201527f2f3e3c6c696e6520636c6173733d22737431222078313d22333134222079313d6104a08201527f2236312e34222078323d22333134222079323d223633342e33222f3e3c6c696e6104c08201527f6520636c6173733d22737431222078313d223430392e35222079313d2236312e6104e08201527f34222078323d223430392e35222079323d223633342e33222f3e3c636972636c6105008201527f6520636c6173733d22737432222063783d223430392e35222063793d223135376105208201527f2220723d22352e34222f3e3c636972636c6520636c6173733d227374322220636105408201527f783d223530352e31222063793d223334372e382220723d22352e34222f3e3c636105608201527f6972636c6520636c6173733d22737432222063783d2232372e33222063793d226105808201527f3533382e372220723d22352e34222f3e3c636972636c6520636c6173733d22736105a08201527f7432222063783d2232372e33222063793d223135362e342220723d22352e34226105c082015261179f60f11b6105e08201526105e20190565b604051602081830303815290604052905090565b6060610b7b611794565b610b836117a5565b610b8b6120a0565b604051602001610b5d93929190612b14565b6060604051602001610b5d907f3c7061746820636c6173733d227374332220643d224d3337382e322c33302e3581527f6c352e342c31392e31682d322e336c2d302e382d332e31483337366c2d302e3860208201527f2c332e31682d322e334c3337382e322c33302e357a204d3338302c34342e356c60408201527f2d312e322d342e386c2d302e352d322e326c2d302e352c322e326c2d312e332c60608201527f342e38483338307a222f3e3c7061746820636c6173733d227374332220643d2260808201527f4d3339352e322c33332e31682d322e39563331683876322e31682d322e39763160a08201527f362e35682d322e325633332e317a222f3e3c7061746820636c6173733d22737460c08201527f332220643d224d3431302e362c333168322e327631362e3568342e387632682d60e08201527f375633317a222f3e3c7061746820636c6173733d227374332220643d224d34326101008201527f372e352c333168362e3276322e31682d342e3176372e3168332e3576322e31686101208201527f2d332e3576352e3368342e3176322e31682d362e325633317a222f3e3c7061746101408201527f6820636c6173733d227374332220643d224d3434342e362c33302e336c352e386101608201527f2c392e376c312e332c322e336c2d302e312d322e3256333168322e327631396c6101808201527f2d352e392d392e376c2d312e332d326c302e312c3276392e33682d322e3256336101a08201527f302e337a222f3e3c7061746820636c6173733d227374332220643d224d3436356101c08201527f2e332c33302e3863312e332c302e312c322e342c302e332c332e352c302e38636101e08201527f312c302e352c312e392c312e312c322e372c312e3963302e372c302e382c312e6102008201527f332c312e382c312e372c322e3963302e342c312e312c302e362c322e342c302e6102208201527f362c332e3963302c312e342d302e322c322e372d302e362c332e39632d302e346102408201527f2c312e312d312c322e312d312e372c322e39632d302e372c302e382d312e362c6102608201527f312e342d322e372c312e39632d312c302e352d322e322c302e372d332e352c306102808201527f2e385633302e387a204d3436372e352c34372e3363302e352d302e322c312d306102a08201527f2e342c312e352d302e3763302e352d302e332c302e392d302e382c312e332d316102c08201527f2e3463302e342d302e362c302e372d312e322c302e392d3263302e322d302e386102e08201527f2c302e342d312e382c302e342d322e3863302d312e312d302e312d322d302e346103008201527f2d322e38632d302e322d302e382d302e352d312e352d302e392d32632d302e346103208201527f2d302e362d302e382d312d312e332d312e34632d302e352d302e332d312d302e6103408201527f362d312e352d302e375634372e337a222f3e3c7061746820636c6173733d22736103608201527f74332220643d224d3438342e342c333168322e327631382e36682d322e3256336103808201527f317a222f3e3c7061746820636c6173733d227374332220643d224d3439382c346103a08201527f362e3863302e342c302e322c302e382c302e342c312e322c302e3663302e342c6103c08201527f302e322c302e392c302e332c312e342c302e3363302e332c302c302e362c302c6103e08201527f302e392d302e3173302e352d302e322c302e372d302e3463302e322d302e322c6104008201527f302e342d302e342c302e352d302e3763302e312d302e332c302e322d302e362c6104208201527f302e322d3163302d302e332c302d302e352d302e312d302e38632d302e312d306104408201527f2e332d302e322d302e362d302e332d302e39632d302e322d302e332d302e332d6104608201527f302e372d302e362d31632d302e322d302e342d302e352d302e382d302e392d316104808201527f2e326c2d312e352d312e39632d302e342d302e352d302e372d302e392d312d316104a08201527f2e34632d302e332d302e342d302e352d302e382d302e362d312e32632d302e326104c08201527f2d302e342d302e332d302e382d302e342d312e31632d302e312d302e342d302e6104e08201527f312d302e372d302e312d312e3163302d302e362c302e312d312e312c302e332d6105008201527f312e3663302e322d302e352c302e352d302e392c302e382d312e3363302e342d6105208201527f302e342c302e382d302e362c312e332d302e3863302e352d302e322c312e312d6105408201527f302e332c312e372d302e3363302e352c302c312c302e312c312e362c302e32636105608201527f302e352c302e312c312c302e342c312e352c302e366c2d302e392c312e38632d6105808201527f302e332d302e322d302e362d302e332d302e392d302e34632d302e332d302e316105a08201527f2d302e372d302e322d312d302e32632d302e362c302d312e312c302e322d312e6105c08201527f352c302e35632d302e342c302e342d302e362c302e392d302e362c312e3563306105e08201527f2c302e322c302c302e342c302e312c302e3663302c302e322c302e312c302e346106008201527f2c302e322c302e3663302e312c302e322c302e322c302e352c302e342c302e376106208201527f63302e322c302e332c302e342c302e362c302e362c302e396c322e322c322e396106408201527f63302e332c302e342c302e352c302e372c302e382c312e3163302e322c302e346106608201527f2c302e352c302e372c302e362c312e3163302e322c302e342c302e332c302e386106808201527f2c302e342c312e3263302e312c302e342c302e322c302e382c302e322c312e336106a08201527f63302c302e372d302e312c312e332d302e332c312e39632d302e322c302e362d6106c08201527f302e352c312d302e392c312e34632d302e342c302e342d302e392c302e372d316106e08201527f2e342c302e39632d302e362c302e322d312e322c302e332d312e382c302e33636107008201527f2d302e372c302d312e332d302e312d322d302e33632d302e362d302e322d312e6107208201527f322d302e352d312e362d302e384c3439382c34362e387a222f3e00000000000061074082015261075a0190565b60606114ad876120b1565b6114b6876120e2565b6114bf866121a8565b6114ca88878761220c565b6040516020016114dd9493929190612b57565b60405160208183030381529060405290509695505050505050565b606081516000141561151857505060408051602081019091526000815290565b6000604051806060016040528060408152602001614a0a60409139905060006003845160026115479190612bc4565b6115519190612bf2565b61155c906004612c06565b9050600061156b826020612bc4565b67ffffffffffffffff811115611583576115836125de565b6040519080825280601f01601f1916602001820160405280156115ad576020820181803683370190505b509050818152600183018586518101602084015b81831015611619576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f81168501518253506001016115c1565b600389510660018114611633576002811461164457611650565b613d3d60f01b600119830152611650565b603d60f81b6000198301525b509398975050505050505050565b60606001600160801b03821661168b5750506040805180820190915260018152600360fc1b602082015290565b8160005b6001600160801b038216156116be57806116a881612c25565b91506116b79050600a83612c4c565b915061168f565b6000816001600160801b031667ffffffffffffffff8111156116e2576116e26125de565b6040519080825280601f01601f19166020018201604052801561170c576020820181803683370190505b508593509050815b6001600160801b0384161561178b5761172e600a85612c72565b611739906030612c98565b60f81b8261174683612cc3565b9250826001600160801b03168151811061176257611762612ce6565b60200101906001600160f81b031916908160001a905350611784600a85612c4c565b9350611714565b50949350505050565b6060604051602001610b5d90612cfc565b6060604051602001610b5d907f3c636972636c65207374796c653d2266696c6c3a23303030304646222063783d81527f22313134222063793d223332302220723d223338222f3e3c6c696e656172477260208201527f616469656e742069643d223722206772616469656e74556e6974733d2275736560408201527f7253706163654f6e557365222078313d223237392e38303038222079313d223160608201527f3230332e303338222078323d223537382e39313239222079323d22313230332e60808201527f30333822206772616469656e745472616e73666f726d3d226d6174726978283060a08201527f2031202d31203020313434342e34303532202d35342e3434363229223e3c737460c08201527f6f7020206f66667365743d223022207374796c653d2273746f702d636f6c6f7260e08201527f3a23464142324445222f3e3c73746f7020206f66667365743d223122207374796101008201527f6c653d2273746f702d636f6c6f723a23303030304646222f3e3c2f6c696e65616101208201527f724772616469656e743e3c636972636c65207374796c653d2266696c6c3a75726101408201527f6c282337293b222063783d223234312e34222063793d223337342e392220723d6101608201527f223134392e36222f3e3c6c696e6561724772616469656e742069643d223822206101808201527f6772616469656e74556e6974733d227573657253706163654f6e5573652220786101a08201527f313d223230322e39353031222079313d223339302e34323039222078323d22316101c08201527f30392e36333533222079323d223438332e37333537223e3c73746f7020206f666101e08201527f667365743d223022207374796c653d2273746f702d636f6c6f723a23304230346102008201527f3433222f3e3c73746f7020206f66667365743d22302e3531373322207374796c6102208201527f653d2273746f702d636f6c6f723a23314231343634222f3e3c73746f7020206f6102408201527f66667365743d223122207374796c653d2273746f702d636f6c6f723a233245336102608201527f313930222f3e3c2f6c696e6561724772616469656e743e3c70617468207374796102808201527f6c653d2266696c6c3a75726c282338293b2220643d224d3230372e382c3339396102a08201527f2e366332372e372c34312e382c33312e352c38382c382e362c3130332e32632d6102c08201527f32332c31352e322d36342d362e332d39312e372d34382e31732d33312e352d386102e08201527f382d382e362d3130332e32433133392c3333362e332c3138302e312c3335372e6103008201527f392c3230372e382c3339392e367a222f3e3c6c696e6561724772616469656e746103208201527f2069643d223922206772616469656e74556e6974733d227573657253706163656103408201527f4f6e557365222078313d223730352e38393035222079313d223834312e3932326103608201527f33222078323d223739372e34393035222079323d223834312e393232332220676103808201527f72616469656e745472616e73666f726d3d226d6174726978282d302e373037316103a08201527f20302e37303731202d302e37303731202d302e3730373120313236332e3134396103c08201527f35203532322e3832303629223e3c73746f7020206f66667365743d22302e32316103e08201527f363522207374796c653d2273746f702d636f6c6f723a23464142324445222f3e6104008201527f3c73746f7020206f66667365743d223122207374796c653d2273746f702d636f6104208201527f6c6f723a23303046464646222f3e3c2f6c696e6561724772616469656e743e3c6104408201527f636972636c65207374796c653d2266696c6c3a75726c282339293b222063783d6104608201527f223133362e33222063793d223435392220723d2234352e38222f3e3c6c696e656104808201527f61724772616469656e742069643d22313022206772616469656e74556e6974736104a08201527f3d227573657253706163654f6e557365222078313d22313538392e39373738226104c08201527f2079313d223831372e3737222078323d22313630352e33343835222079323d226104e08201527f3836302e3534303522206772616469656e745472616e73666f726d3d226d61746105008201527f726978282d302e39383332202d302e3138323520302e31383235202d302e39386105208201527f333220313739392e3832353120313437312e3032333129223e3c73746f7020206105408201527f6f66667365743d223022207374796c653d2273746f702d636f6c6f723a2330426105608201527f30343433222f3e3c73746f7020206f66667365743d22302e35313733222073746105808201527f796c653d2273746f702d636f6c6f723a23314231343634222f3e3c73746f70206105a08201527f206f66667365743d223122207374796c653d2273746f702d636f6c6f723a23326105c08201527f4533313930222f3e3c2f6c696e6561724772616469656e743e3c636972636c656105e08201527f207374796c653d2266696c6c3a75726c28233130293b222063783d223338312e6106008201527f34222063793d223334392e382220723d2232322e31222f3e3c6c696e656172476106208201527f72616469656e742069643d22313122206772616469656e74556e6974733d22756106408201527f73657253706163654f6e557365222078313d223232352e36393634222079313d6106608201527f223230312e30373339222078323d223232372e34393334222079323d223237326106808201527f2e30353439223e3c73746f7020206f66667365743d223022207374796c653d226106a08201527f73746f702d636f6c6f723a23464336454330222f3e3c73746f7020206f6666736106c08201527f65743d223122207374796c653d2273746f702d636f6c6f723a233943303035446106e08201527f222f3e3c2f6c696e6561724772616469656e743e3c636972636c65207374796c6107008201527f653d2266696c6c3a75726c28233131293b222063783d223232362e3722206379610720820152721e91191a18171c1110391e91199a171b91179f60691b6107408201526107530190565b6060604051602001610b5d90613834565b60606120bc8261165e565b6040516020016120cc919061422c565b6040516020818303038152906040529050919050565b60008181526020819052604081208054606092919061210090612479565b80601f016020809104026020016040519081016040528092919081815260200182805461212c90612479565b80156121795780601f1061214e57610100808354040283529160200191612179565b820191906000526020600020905b81548152906001019060200180831161215c57829003601f168201915b5050505050905080604051602001612191919061447f565b604051602081830303815290604052915050919050565b6060662386f26fc10000655af3107a40006121cb6121c68386612c4c565b61165e565b6121e3826121d98588612c72565b6121c69190612c4c565b6040516020016121f49291906145c5565b60405160208183030381529060405292505050919050565b6060670de0b6b3a7640000662386f26fc1000061222c6121c68387612c4c565b61223a826121d98589612c72565b876122486121c68689612c4c565b612256856121d9888b612c72565b8a60405160200161226c9695949392919061473e565b604051602081830303815290604052925050509392505050565b82805461229290612479565b90600052602060002090601f0160209004810192826122b457600085556122fa565b82601f106122cd5782800160ff198235161785556122fa565b828001600101855582156122fa579182015b828111156122fa5782358255916020019190600101906122df565b5061230692915061230a565b5090565b5b80821115612306576000815560010161230b565b60006020828403121561233157600080fd5b5035919050565b60005b8381101561235357818101518382015260200161233b565b83811115612362576000848401525b50505050565b6020815260008251806020840152612387816040850160208701612338565b601f01601f19169190910160400192915050565b6000806000604084860312156123b057600080fd5b833567ffffffffffffffff808211156123c857600080fd5b818601915086601f8301126123dc57600080fd5b8135818111156123eb57600080fd5b8760208285010111156123fd57600080fd5b6020928301989097509590910135949350505050565b6001600160a01b038116811461242857600080fd5b50565b6001600160801b038116811461242857600080fd5b6000806040838503121561245357600080fd5b823561245e81612413565b9150602083013561246e8161242b565b809150509250929050565b600181811c9082168061248d57607f821691505b602082108114156124ae57634e487b7160e01b600052602260045260246000fd5b50919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260006124f16020830184866124b4565b949350505050565b60408152600061250d6040830185876124b4565b9050826020830152949350505050565b600080600080600080600060e0888a03121561253857600080fd5b87519650602088015161254a8161242b565b604089015190965061255b8161242b565b606089015190955061256c81612413565b608089015190945061257d8161242b565b60a089015190935061258e8161242b565b60c089015190925061259f8161242b565b8091505092959891949750929550565b600080604083850312156125c257600080fd5b82516125cd8161242b565b602084015190925061246e8161242b565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561260657600080fd5b815167ffffffffffffffff8082111561261e57600080fd5b818401915084601f83011261263257600080fd5b815181811115612644576126446125de565b604051601f8201601f19908116603f0116810190838211818310171561266c5761266c6125de565b8160405282815287602084870101111561268557600080fd5b612696836020830160208801612338565b979650505050505050565b600081516126b3818560208601612338565b9290920192915050565b7f3c7376672076657273696f6e3d22312e31222069643d224c617965725f31222081527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660208201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260408201527f672f313939392f786c696e6b2220783d223070782220793d223070782220766960608201527f6577426f783d2230203020353332203735342e3522207374796c653d22656e6160808201527f626c652d6261636b67726f756e643a6e65772030203020353332203735342e3560a08201527f3b2220786d6c3a73706163653d227072657365727665223e000000000000000060c0820152600085516127d98160d8850160208a01612338565b8551908301906127f08160d8840160208a01612338565b85519101906128068160d8840160208901612338565b845191019061281c8160d8840160208801612338565b61283760d882840101651e17b9bb339f60d11b815260060190565b98975050505050505050565b727b226e616d65223a22506f736974696f6e202360681b8152835160009060206128738260138601838a01612338565b7f222c226465736372697074696f6e223a224120506f736974696f6e206f6e20746013928501928301527f68652041746c656e6469732070726f746f636f6c20666f7220706f6f6c20000060338301528554605190600090600181811c90808316806128e057607f831692505b8683108114156128fe57634e487b7160e01b85526022600452602485fd5b808015612912576001811461292757612958565b60ff1985168988015283890187019550612958565b60008d81526020902060005b8581101561294e5781548b82018a0152908401908901612933565b505086848a010195505b50507f2e2054686973204e465420726570726573656e747320796f7572207368617265845250507f206f662074686520706f6f6c2c20697473207468656f7269746963616c2070726020830152507f69636520646570656e6473206f6e2074686520737461747573206f662074686560408201527f20706f6f6c2c202074686520616d6f756e74206f6620746f6b656e7320796f7560608201527f206f726967696e616c6c79206465706f736974656420616e642074686520646960808201527f66666572656e74207265776172647320616c6c6f636174656420746f2069742e60a08201527f2265787465726e616c5f75726c223a2268747470733a2f2f6170702e61746c6560c08201527f6e6469732e696f2f222c22696d616765223a2022646174613a696d6167652f7360e08201526d1d99cade1b5b0ed8985cd94d8d0b60921b610100820152612ac2612ab461010e83015b896126a1565b61227d60f01b815260020190565b9998505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612b0781601d850160208701612338565b91909101601d0192915050565b60008451612b26818460208901612338565b845190830190612b3a818360208901612338565b8451910190612b4d818360208801612338565b0195945050505050565b60008551612b69818460208a01612338565b855190830190612b7d818360208a01612338565b8551910190612b90818360208901612338565b8451910190612ba3818360208801612338565b019695505050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612bd757612bd7612bae565b500190565b634e487b7160e01b600052601260045260246000fd5b600082612c0157612c01612bdc565b500490565b6000816000190483118215151615612c2057612c20612bae565b500290565b60006001600160801b0380831681811415612c4257612c42612bae565b6001019392505050565b60006001600160801b0380841680612c6657612c66612bdc565b92169190910492915050565b60006001600160801b0380841680612c8c57612c8c612bdc565b92169190910692915050565b60006001600160801b03808316818516808303821115612cba57612cba612bae565b01949350505050565b60006001600160801b03821680612cdc57612cdc612bae565b6000190192915050565b634e487b7160e01b600052603260045260246000fd5b7f3c6c696e6561724772616469656e742069643d223122206772616469656e745581527f6e6974733d227573657253706163654f6e557365222078313d223530322e383660208201527f3634222079313d223438352e36303537222078323d223538372e38303139222060408201527f79323d223438352e3630353722206772616469656e745472616e73666f726d3d60608201527f226d6174726978282d302e37303936202d302e3730343620302e37303436202d60808201527f302e37303936203134372e39313939203835382e3139323129223e3c73746f7060a08201527f20206f66667365743d223022207374796c653d2273746f702d636f6c6f723a2360c082018190527f464142324445222f3e3c73746f7020206f66667365743d223122207374796c6560e08301527f3d2273746f702d636f6c6f723a23303030304646222f3e3c2f6c696e656172476101008301527f72616469656e743e3c636972636c65207374796c653d2266696c6c3a75726c286101208301527f2331293b222063783d223130332e31222063793d223132392e342220723d22346101408301527f322e35222f3e3c6c696e6561724772616469656e742069643d223222206772616101608301527f6469656e74556e6974733d227573657253706163654f6e557365222078313d226101808301527f343835332e383335222079313d223938342e35383333222078323d22343835346101a08301527f2e38323138222079323d22313032332e3535383822206772616469656e7454726101c08301527f616e73666f726d3d226d6174726978282d302e39373732202d302e32313233206101e08301527f302e32313233202d302e3937373220343636372e3036303520323232382e31356102008301527f353329223e3c73746f7020206f66667365743d223022207374796c653d2273746102208301527f6f702d636f6c6f723a23303046464646222f3e3c73746f7020206f66667365746102408301527f3d223122207374796c653d2273746f702d636f6c6f723a23464646463030222f6102608301527f3e3c2f6c696e6561724772616469656e743e3c636972636c65207374796c653d6102808301527f2266696c6c3a75726c282332293b222063783d223133362e37222063793d22326102a08301527f31352e332220723d223139222f3e3c6c696e6561724772616469656e742069646102c08301527f3d223322206772616469656e74556e6974733d227573657253706163654f6e556102e08301527f7365222078313d223639372e31303838222079313d223638352e3632353722206103008301527f78323d223738342e36383237222079323d223638352e363235372220677261646103208301527f69656e745472616e73666f726d3d226d6174726978282d322e3034323620302e6103408301527f36373637202d302e37343331202d302e3833353320323237322e3033313220326103608301527f36342e3638343429223e3c73746f70206f66667365743d223022207374796c656103808301527f3d2273746f702d636f6c6f723a23303046464646222f3e3c73746f7020206f666103a08301527f667365743d223122207374796c653d2273746f702d636f6c6f723a23394446436103c08301527f3932222f3e3c2f6c696e6561724772616469656e743e3c6c696e65207374796c6103e08301527f653d2266696c6c3a6e6f6e653b7374726f6b653a75726c282333293b7374726f6104008301527f6b652d77696474683a342e3134323b7374726f6b652d6c696e656361703a726f6104208301527f756e643b7374726f6b652d6c696e656a6f696e3a726f756e643b7374726f6b656104408301527f2d6d697465726c696d69743a31303b222078313d223334322e36222079313d226104608301527f3137342e32222078323d223135352e39222079323d223231322e34222f3e3c6c6104808301527f696e6561724772616469656e742069643d223422206772616469656e74556e696104a08301527f74733d227573657253706163654f6e557365222078313d223334382e373632386104c08301527f222079313d223131392e37373634222078323d223335302e38383939222079326104e08301527f3d223230332e37393833223e3c73746f7020206f66667365743d2230222073746105008301527f796c653d2273746f702d636f6c6f723a23303046464646222f3e3c73746f70206105208301527f206f66667365743d223122207374796c653d2273746f702d636f6c6f723a23306105408301527f3030304646222f3e3c2f6c696e6561724772616469656e743e3c636972636c656105608301527f207374796c653d2266696c6c3a75726c282334293b222063783d2233353022206105808301527f63793d223136362e382220723d223431222f3e3c636972636c65207374796c656105a08301527f3d2266696c6c3a234646464630303b222063783d223335342e38222063793d226105c08301527f37302220723d22352e39222f3e3c6c696e6561724772616469656e742069643d6105e08301527f223522206772616469656e74556e6974733d227573657253706163654f6e55736106008301527f65222078313d223134302e37373536222079313d223233302e313132322220786106208301527f323d223232382e39343132222079323d223233302e31313232223e3c73746f706106408301526106608201527f394446433932222f3e3c73746f7020206f66667365743d223122207374796c656106808201527f3d2273746f702d636f6c6f723a23464637424143222f3e3c2f6c696e656172476106a08201527f72616469656e743e3c6c696e65207374796c653d2266696c6c3a6e6f6e653b736106c08201527f74726f6b653a75726c282335293b7374726f6b652d77696474683a342e3733336106e08201527f373b7374726f6b652d6c696e656361703a726f756e643b7374726f6b652d6c696107008201527f6e656a6f696e3a726f756e643b7374726f6b652d6d697465726c696d69743a316107208201527f303b222078313d223134332e31222079313d223231392e32222078323d2232326107408201527f362e36222079323d223234312e31222f3e3c6c696e6561724772616469656e746107608201527f2069643d223622206772616469656e74556e6974733d227573657253706163656107808201527f4f6e557365222078313d223639352e30323834222079313d223831322e3737356107a08201527f35222078323d223738332e37383538222079323d223831322e373735352220676107c08201527f72616469656e745472616e73666f726d3d226d6174726978282d312e313733376107e08201527f20302e39363937202d302e38323434202d302e3634313220313832322e3437346108008201526a101898971b9c9c1b14911f60a91b6108208201527f3c73746f7020206f66667365743d223022207374796c653d2273746f702d636f61082b8201527f6c6f723a23333533444637222f3e3c73746f7020206f66667365743d2231222061084b8201527f7374796c653d2273746f702d636f6c6f723a23464637424143222f3e3c2f6c6961086b8201527f6e6561724772616469656e743e3c6c696e65207374796c653d2266696c6c3a6e61088b8201527f6f6e653b7374726f6b653a75726c282336293b7374726f6b652d77696474683a6108ab8201527f352e333235343b7374726f6b652d6c696e656361703a726f756e643b7374726f6108cb8201527f6b652d6c696e656a6f696e3a726f756e643b7374726f6b652d6d697465726c696108eb8201527f6d69743a31303b222078313d223334322e36222079313d223137342e3222207861090b82015275191e9119191b171b11103c991e91191a18971891179f60511b61092b820152600061094182015b92915050565b7f3c6c696e6561724772616469656e742069643d22313222206772616469656e7481527f556e6974733d227573657253706163654f6e557365222078313d223438342e3160208201527f323733222079313d223239352e35353132222078323d223438352e333939342260408201527f2079323d223334352e3739353922206772616469656e745472616e73666f726d60608201527f3d226d617472697828302e3930343520302e34323636202d302e34323636203060808201527f2e39303435203139332e33333039202d34372e30353529223e3c73746f70202060a08201527f6f66667365743d223022207374796c653d2273746f702d636f6c6f723a23464360c08201527f36454330222f3e3c73746f7020206f66667365743d223122207374796c653d2260e08201527f73746f702d636f6c6f723a23394330303544222f3e3c2f6c696e6561724772616101008201527f6469656e743e3c636972636c65207374796c653d2266696c6c3a75726c2823316101208201527f32293b222063783d223439332e38222063793d223435322e352220723d2232346101408201527f2e35222f3e3c6c696e6561724772616469656e742069643d22313322206772616101608201527f6469656e74556e6974733d227573657253706163654f6e557365222078313d226101808201527f3532382e30383732222079313d223434342e33343034222078323d223532392e6101a08201527f30383934222079323d223438332e3932323722206772616469656e745472616e6101c08201527f73666f726d3d226d617472697828302e3930343520302e34323636202d302e346101e08201527f32363620302e39303435203139332e33333039202d34372e30353529223e3c736102008201527f746f7020206f66667365743d223022207374796c653d2273746f702d636f6c6f6102208201527f723a23303046464646222f3e3c73746f7020206f66667365743d2231222073746102408201527f796c653d2273746f702d636f6c6f723a23303030304646222f3e3c2f6c696e656102608201527f61724772616469656e743e3c636972636c65207374796c653d2266696c6c3a756102808201527f726c28233133293b222063783d223437322e35222063793d223630302e3422206102a08201527f723d2231392e33222f3e3c6c696e6561724772616469656e742069643d2231346102c08201527f22206772616469656e74556e6974733d227573657253706163654f6e557365226102e08201527f2078313d22313031372e34333134222079313d223435332e32363231222078326103008201527f3d22313130362e31383837222079323d223435332e32363231222067726164696103208201527f656e745472616e73666f726d3d226d6174726978282d302e3834393720302e316103408201527f333938202d382e323539333936652d3032202d302e3938373620313336392e366103608201527f353938203839332e3739373929223e3c73746f7020206f66667365743d2230226103808201527f207374796c653d2273746f702d636f6c6f723a23344336464635222f3e3c73746103a08201527f6f7020206f66667365743d22302e3336333422207374796c653d2273746f702d6103c08201527f636f6c6f723a23344134464431222f3e3c73746f7020206f66667365743d22316103e08201527f22207374796c653d2273746f702d636f6c6f723a23343531303841222f3e3c2f6104008201527f6c696e6561724772616469656e743e3c6c696e65207374796c653d2266696c6c6104208201527f3a6e6f6e653b7374726f6b653a75726c28233134293b7374726f6b652d7769646104408201527f74683a352e333235343b7374726f6b652d6c696e656361703a726f756e643b736104608201527f74726f6b652d6c696e656a6f696e3a726f756e643b7374726f6b652d6d6974656104808201527f726c696d69743a31303b222078313d223436362e34222079313d223539392e356104a08201527f222078323d223339332e37222079323d223538392e36222f3e3c6c696e6561726104c08201527f4772616469656e742069643d22313522206772616469656e74556e6974733d226104e08201527f7573657253706163654f6e557365222078313d223534352e34383433222079316105008201527f3d223631372e33353437222078323d223633342e32343136222079323d2236316105208201527f372e3335343722206772616469656e745472616e73666f726d3d226d617472696105408201527f78282d312e3139343320312e35363733202d312e30343832202d302e333136206105608201527f313737382e32303534202d3230392e3538323929223e3c73746f7020206f66666105808201527f7365743d223022207374796c653d2273746f702d636f6c6f723a2341413436386105a08201527f38222f3e3c73746f7020206f66667365743d223122207374796c653d2273746f6105c08201527f702d636f6c6f723a23333533444637222f3e3c2f6c696e6561724772616469656105e08201527f6e743e3c6c696e65207374796c653d2266696c6c3a6e6f6e653b7374726f6b656106008201527f3a75726c28233135293b7374726f6b652d77696474683a352e333235343b73746106208201527f726f6b652d6c696e656361703a726f756e643b7374726f6b652d6c696e656a6f6106408201527f696e3a726f756e643b7374726f6b652d6d697465726c696d69743a31303b22206106608201527f78313d223438372e39222079313d223435372e39222078323d223336352e33226106808201527f2079323d223538312e37222f3e3c6c696e6561724772616469656e742069643d6106a08201527f22313622206772616469656e74556e6974733d227573657253706163654f6e556106c08201527f7365222078313d223432332e35383733222079313d223534392e3331343822206106e08201527f78323d223432342e37313637222079323d223434332e313530322220677261646107008201527f69656e745472616e73666f726d3d226d617472697828302e3930343520302e346107208201527f323636202d302e3432363620302e39303435203139332e33333039202d34372e61074082015265181a9a94911f60d11b6107608201527f3c73746f7020206f66667365743d22392e353935393630652d303222207374796107668201527f6c653d2273746f702d636f6c6f723a23333831303737222f3e3c73746f7020206107868201527f6f66667365743d223122207374796c653d2273746f702d636f6c6f723a2337436107a68201527f31444339222f3e3c2f6c696e6561724772616469656e743e3c636972636c65206107c68201527f7374796c653d2266696c6c3a75726c28233136293b222063783d223336352e386107e68201527f222063793d223538312e362220723d2233392e33222f3e000000000000000000610806820152600061081d820161382e565b7f3c6c696e6561724772616469656e742069643d22313722206772616469656e7481527f556e6974733d227573657253706163654f6e557365222078313d2233382e373160208201527f3732222079313d22322e37343633222078323d223130322e353239222079323d60408201527f2236362e35353831223e3c73746f7020206f66667365743d22302e323136352260608201527f207374796c653d2273746f702d636f6c6f723a23464142324445222f3e3c737460808201527f6f7020206f66667365743d223122207374796c653d2273746f702d636f6c6f7260a08201527f3a23303046464646222f3e3c2f6c696e6561724772616469656e743e3c70617460c08201527f68207374796c653d2266696c6c3a75726c28233137293b2220643d224d31323160e08201527f2e322c35342e314832382e38632d302e392c302d312e372d302e372d312e372d6101008201527f312e375632352e3563302d302e392c302e372d312e372c312e372d312e3768396101208201527f322e3463302e392c302c312e372c302e372c312e372c312e377632362e3943316101408201527f32322e382c35332e342c3132322e312c35342e312c3132312e322c35342e317a6101608201527f222f3e3c74657874207472616e73666f726d3d226d61747269782831203020306101808201527f20312034312e393934332034332e37313036292220636c6173733d22737435226101a08201526401f24a21d160dd1b6101c082015260006144786144656101c58401856126a1565b661e17ba32bc3a1f60c91b815260070190565b9392505050565b7f3c7061746820636c6173733d227374312220643d224d32392e322c3634322e3781527f683335362e3763312e312c302c322e312c312e332c322e312c322e387632342e60208201527f3763302c312e352d312c322e382d322e312c322e384832392e32632d312e312c60408201527f302d322e312d312e332d322e312d322e38762d32342e374332372e312c36343360608201527f2e392c32382c3634322e372c32392e322c3634322e377a222f3e3c746578742060808201527f7472616e73666f726d3d226d617472697828312030203020312033372e35303660a08201527f35203636332e35343237292220636c6173733d2273743320737435223e506f6f60c0820152620361d160ed1b60e0820152600082516145a78160e3850160208701612338565b661e17ba32bc3a1f60c91b60e393909101928301525060ea01919050565b7f3c7061746820636c6173733d227374312220643d224d3339382e312c3634322e81527f38683130342e3563312e312c302c312e392c302e392c312e392c312e3976323660208201527f2e3463302c312e312d302e392c312e392d312e392c312e39483339382e31632d60408201527f312e312c302d312e392d302e392d312e392d312e39762d32362e34433339362e60608201527f322c3634332e372c3339372e312c3634322e382c3339382e312c3634322e387a60808201527f222f3e3c74657874207472616e73666f726d3d226d617472697828312030203060a08201527f2031203432302e33323631203636322e34363739292220636c6173733d22737460c08201526b0199039ba1a911f24972917160a51b60e0820152600083516146f68160ec850160208801612338565b601760f91b60ec9184019182015283516147178160ed840160208801612338565b61473460ed8284010167129e17ba32bc3a1f60c11b815260080190565b9695505050505050565b7f3c7061746820636c6173733d227374312220643d224d3235392e382c3731312e81527f364832392e39632d312e332c302d322e332d312e362d322e332d332e35762d3260208201527f332e3263302d322c312d332e352c322e332d332e35683232392e3963312e332c60408201527f302c322e332c312e362c322e332c332e357632332e32433236322e312c37313060608201527f2c3236312c3731312e362c3235392e382c3731312e367a222f3e3c746578742060808201527f7472616e73666f726d3d226d617472697828312030203020312033382e30333060a08201527f34203730322e31393235292220636c6173733d2273743320737435223e00000060c08201526000875161485a8160dd850160208c01612338565b601760f91b60dd91840191820152875161487b8160de840160208c01612338565b6149fb6149de6149d8612aae6149cb6149c561489c60de888a01018f6126a1565b7f204465706f7369746564203c2f746578743e3c7061746820636c6173733d227381527f74312220643d224d3530312e382c3731312e36483237312e32632d312e332c3060208201527f2d322e332d312e362d322e332d332e35762d32332e3263302d322c312d332e3560408201527f2c322e332d332e35683233302e3763312e332c302c322e332c312e362c322e3360608201527f2c332e357632332e32433530342e312c3731302c3530332e312c3731312e362c60808201527f3530312e382c3731312e367a222f3e3c74657874207472616e73666f726d3d2260a08201527f6d61747269782831203020302031203237382e38393331203730322e3139313960c08201527214911031b630b9b99e9139ba199039ba1a911f60691b60e082015260f30190565b8c6126a1565b601760f91b815260010190565b876126a1565b70102137b93937bbb2b2101e17ba32bc3a1f60791b815260110190565b9a995050505050505050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122041221d56a1c68bedd9835b02245ea1228543a9091a2f8f9d952f5b56a7aae03064736f6c63430008090033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.