├── funding.json ├── remappings.txt ├── foundry.toml ├── .gitignore ├── src ├── interfaces │ ├── IOCO.sol │ ├── IPileus.sol │ └── IWorldID.sol ├── MockWorldID.sol ├── helpers │ └── ByteHasher.sol ├── ERC721Votes.sol ├── verifiers │ └── WorldIDVerifier.sol ├── OCO.sol ├── Votes.sol ├── Pileus.sol ├── ERC721.sol └── TOTC.sol ├── .gitmodules ├── test └── MockWorldID.t.sol ├── .github └── workflows │ └── test.yml ├── LICENSE.txt ├── README.md ├── script └── Deploy.s.sol └── broadcast └── Deploy.s.sol └── 480 ├── run-1749684859.json └── run-1744428937.json /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0xc55da0ccb43d29814ac5ac3e1eacb85a5008a30df7fff6c34c45684c89ad5f11" 4 | } 5 | } -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ 2 | @openzeppelin/community-contracts/=lib/openzeppelin-community-contracts/contracts/ -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "src" 3 | out = "out" 4 | libs = ["lib"] 5 | optimizer = true 6 | 7 | # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Docs 11 | docs/ 12 | 13 | # Dotenv file 14 | .env 15 | -------------------------------------------------------------------------------- /src/interfaces/IOCO.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.22; 3 | 4 | interface IOCO { 5 | function mint(address to, uint256 amount) external; 6 | function trackBurn(address to, uint256 amount) external; 7 | } 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/openzeppelin-contracts"] 5 | path = lib/openzeppelin-contracts 6 | url = https://github.com/OpenZeppelin/openzeppelin-contracts 7 | [submodule "lib/openzeppelin-community-contracts"] 8 | path = lib/openzeppelin-community-contracts 9 | url = https://github.com/OpenZeppelin/openzeppelin-community-contracts 10 | -------------------------------------------------------------------------------- /src/MockWorldID.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import {IWorldID} from "./interfaces/IWorldID.sol"; 5 | 6 | contract MockWorldID is IWorldID { 7 | function verifyProof( 8 | uint256 root, 9 | uint256 groupId, 10 | uint256 signalHash, 11 | uint256 nullifierHash, 12 | uint256 externalNullifierHash, 13 | uint256[8] calldata proof 14 | ) external view {} 15 | } 16 | -------------------------------------------------------------------------------- /src/helpers/ByteHasher.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.21; 3 | 4 | library ByteHasher { 5 | /// @dev Creates a keccak256 hash of a bytestring. 6 | /// @param value The bytestring to hash 7 | /// @return The hash of the specified value 8 | /// @dev `>> 8` makes sure that the result is included in our field 9 | function hashToField(bytes memory value) internal pure returns (uint256) { 10 | return uint256(keccak256(abi.encodePacked(value))) >> 8; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/MockWorldID.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import {Test} from "forge-std/Test.sol"; 5 | import {MockWorldID} from "../src/MockWorldID.sol"; 6 | 7 | contract WorldIDVerifierTest is Test { 8 | MockWorldID private worldId; 9 | 10 | function setUp() public { 11 | worldId = new MockWorldID(); 12 | } 13 | 14 | function test_verifyProof() public view { 15 | worldId.verifyProof(0, 0, 0, 0, 0, [uint256(0), 0, 0, 0, 0, 0, 0, 0]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/interfaces/IPileus.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.22; 3 | 4 | interface IPileus { 5 | function EPOCH_DURATION() external view returns (uint48); 6 | function propsOf(uint256 tokenId) external view returns (address, uint48); 7 | function getApproved(uint256 tokenId) external view returns (address); 8 | function getPastTotalSupply(uint256 timepoint) external view returns (uint256); 9 | function getTotalSupply() external view returns (uint256); 10 | function isApprovedForAll(address owner, address operator) external view returns (bool); 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | env: 9 | FOUNDRY_PROFILE: ci 10 | 11 | jobs: 12 | check: 13 | strategy: 14 | fail-fast: true 15 | 16 | name: Foundry project 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | submodules: recursive 22 | 23 | - name: Install Foundry 24 | uses: foundry-rs/foundry-toolchain@v1 25 | 26 | - name: Show Forge version 27 | run: | 28 | forge --version 29 | 30 | - name: Run Forge fmt 31 | run: | 32 | forge fmt --check 33 | id: fmt 34 | 35 | - name: Run Forge build 36 | run: | 37 | forge build --sizes 38 | id: build 39 | 40 | - name: Run Forge tests 41 | run: | 42 | forge test -vvv 43 | id: test 44 | -------------------------------------------------------------------------------- /src/interfaces/IWorldID.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.21; 3 | 4 | interface IWorldID { 5 | /// @notice Reverts if the zero-knowledge proof is invalid. 6 | /// @param root The of the Merkle tree 7 | /// @param groupId The id of the Semaphore group 8 | /// @param signalHash A keccak256 hash of the Semaphore signal 9 | /// @param nullifierHash The nullifier hash 10 | /// @param externalNullifierHash A keccak256 hash of the external nullifier 11 | /// @param proof The zero-knowledge proof 12 | /// @dev Note that a double-signaling check is not included here, and should be carried by the caller. 13 | function verifyProof( 14 | uint256 root, 15 | uint256 groupId, 16 | uint256 signalHash, 17 | uint256 nullifierHash, 18 | uint256 externalNullifierHash, 19 | uint256[8] calldata proof 20 | ) external view; 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Pileum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pileum Smart Contracts 2 | 3 | - **[ERC721](src/ERC721.sol)**: A modified version of the [OpenZeppelin ERC721 contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.1.0/contracts/token/ERC721/ERC721.sol) that implements an epoch mechanism. 4 | - **[ERC721Votes](src/ERC721Votes.sol)**: A modified version of the [OpenZeppelin ERC721Votes contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.1.0/contracts/token/ERC721/extensions/ERC721Votes.sol) with epoch support. 5 | - **[Votes](src/Votes.sol)**: A modified version of the [OpenZeppelin Votes contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.1.0/contracts/governance/utils/Votes.sol) that adds epoch functionality. 6 | - **[Pileus](src/Pileus.sol)**: An `ERC721` token whose validity is limited to the epoch (e.g., year) of minting. 7 | - **[WorldIDVerifier](src/verifiers/WorldIDVerifier.sol)**: Verifies [World ID proofs](https://docs.world.org/world-id/) and issues **Pileus** tokens. 8 | - **[MockWorldID](src/MockWorldID.sol)**: A mock implementation of the [World ID Router](https://docs.world.org/world-id/id/on-chain) for development purposes. Implements the `IWorldID` interface. 9 | - **[OCO](src/OCO.sol)**: An `ERC20` token with burn tracking functionality. 10 | - **[TOTC](src/TOTC.sol)**: Manages **OCO** token allowances based on the supply of **Pileus** tokens. 11 | 12 | --- 13 | -------------------------------------------------------------------------------- /script/Deploy.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import {Script} from "forge-std/Script.sol"; 5 | import {Pileus} from "../src/Pileus.sol"; 6 | import {WorldIDVerifier} from "../src/verifiers/WorldIDVerifier.sol"; 7 | import {MockWorldID} from "../src/MockWorldID.sol"; 8 | import {IWorldID} from "../src/interfaces/IWorldID.sol"; 9 | import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; 10 | import {TOTC} from "../src/TOTC.sol"; 11 | import {OCO} from "../src/OCO.sol"; 12 | import {IPileus} from "../src/interfaces/IPileus.sol"; 13 | 14 | contract DeployScript is Script { 15 | uint48 private constant BLOCK_TIME = 2; //unit: seconds 16 | uint48 private constant EPOCH_DURATION = 15_778_800; //unit: blocks 17 | uint128 private constant INITIAL_ALLOWANCE = 4_888_405 * 10 ** 18; //unit: tokens 18 | uint128 private constant TARGET_ALLOWANCE = 2_813_664 * 10 ** 18; //unit: tokens 19 | uint128 private constant TARGET_DATE = 10; //unit: epoch count 20 | bytes32 salt = keccak256("Servos ad pileum vocare"); 21 | address initialOwner; 22 | IWorldID worldId; 23 | string worldAppId; 24 | 25 | function setUp() public { 26 | initialOwner = msg.sender; // use --sender 27 | worldAppId = vm.envString("WORLD_APP_ID"); 28 | worldId = IWorldID(vm.envAddress("WORLD_ID_ROUTER_ADDR")); 29 | } 30 | 31 | function run() public { 32 | vm.startBroadcast(); 33 | 34 | //Deploy Pileus contract 35 | Pileus pileus = new Pileus{salt: salt}(initialOwner, EPOCH_DURATION, BLOCK_TIME); 36 | 37 | //Deploy OCO contract 38 | OCO oco = new OCO{salt: salt}(initialOwner); 39 | 40 | //Deploy TOTC contract 41 | uint256 startEpoch = (block.number / EPOCH_DURATION); 42 | (int256 slope, int256 intercept) = 43 | getLinearParams(startEpoch, INITIAL_ALLOWANCE, startEpoch + TARGET_DATE, TARGET_ALLOWANCE); 44 | TOTC totc = new TOTC{salt: salt}(initialOwner, IPileus(address(pileus)), oco, slope, intercept); 45 | oco.grantRole(oco.MINTER_ROLE(), address(totc)); 46 | 47 | //Deploy WorldIDVerifier contract 48 | WorldIDVerifier worldVerifier = new WorldIDVerifier{salt: salt}(worldId, worldAppId, pileus); 49 | pileus.grantRole(pileus.VERIFIER_ROLE(), address(worldVerifier)); 50 | 51 | vm.stopBroadcast(); 52 | } 53 | 54 | function getLinearParams(uint256 x1, uint256 y1, uint256 x2, uint256 y2) 55 | public 56 | pure 57 | returns (int256 slope, int256 intercept) 58 | { 59 | require(x1 < x2, "x1 must be lower than x2"); 60 | uint256 Q128 = 1 << 128; 61 | uint256 absDy = (y1 < y2 ? y2 - y1 : y1 - y2); 62 | uint256 absSlope = Math.mulDiv(absDy, Q128, x2 - x1); 63 | slope = (y1 < y2 ? int256(absSlope) : -int256(absSlope)); 64 | intercept = (int256(y1) * int256(Q128)) - (slope * int256(x1)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ERC721Votes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/extensions/ERC721Votes.sol) 3 | // Modified for pileum.org 4 | pragma solidity ^0.8.20; 5 | 6 | import {ERC721} from "./ERC721.sol"; 7 | import {Votes} from "./Votes.sol"; 8 | 9 | /** 10 | * @dev Extension of ERC-721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts 11 | * as 1 vote unit. 12 | * 13 | * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost 14 | * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of 15 | * the votes in governance decisions, or they can delegate to themselves to be their own representative. 16 | */ 17 | abstract contract ERC721Votes is ERC721, Votes { 18 | uint48 public immutable EPOCH_DURATION; 19 | 20 | constructor(uint48 epochDuration) { 21 | require(epochDuration > 1, "Invalid epoch duration"); 22 | EPOCH_DURATION = epochDuration; 23 | } 24 | 25 | /** 26 | * @dev See {ERC721-_update}. Adjusts votes when tokens are transferred. 27 | * 28 | * Emits a {IVotes-DelegateVotesChanged} event. 29 | */ 30 | function _update(address to, uint256 tokenId, address auth, uint48 timepoint) 31 | internal 32 | virtual 33 | override 34 | returns (address) 35 | { 36 | address previousOwner = super._update(to, tokenId, auth, timepoint); 37 | _transferVotingUnits(previousOwner, to, 1, epoch(timepoint)); 38 | 39 | return previousOwner; 40 | } 41 | 42 | function balanceOf(address owner) public view returns (uint256) { 43 | return balanceOf(owner, currEpoch()); 44 | } 45 | 46 | function epochRange(uint48 timepoint) public view returns (uint48, uint48) { 47 | uint48 start = (timepoint / EPOCH_DURATION) * EPOCH_DURATION; 48 | uint48 end = start + EPOCH_DURATION; 49 | return (start, end); 50 | } 51 | 52 | function epoch(uint48 timepoint) public view override returns (uint32) { 53 | return uint32(timepoint / EPOCH_DURATION); 54 | } 55 | 56 | function currEpoch() public view override returns (uint32) { 57 | return epoch(clock()); 58 | } 59 | 60 | function nextEpoch() public view returns (uint32) { 61 | return epoch(clock() + EPOCH_DURATION); 62 | } 63 | 64 | function epochAddress(address account, uint48 timepoint) internal view override(ERC721, Votes) returns (uint256) { 65 | return (uint256(epoch(timepoint)) << 160) | uint256(uint160(account)); 66 | } 67 | 68 | function epochIndexAddress(address account, uint32 epochIndex) 69 | internal 70 | pure 71 | override(ERC721, Votes) 72 | returns (uint256) 73 | { 74 | return (uint256(epochIndex) << 160) | uint256(uint160(account)); 75 | } 76 | 77 | function getTotalSupply() public view returns (uint256) { 78 | return _getTotalSupply(); 79 | } 80 | 81 | /** 82 | * @dev Returns the balance of `account`. 83 | * 84 | * WARNING: Overriding this function will likely result in incorrect vote tracking. 85 | */ 86 | function _getVotingUnits(address account) internal view virtual override returns (uint256) { 87 | return balanceOf(account); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/verifiers/WorldIDVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import {Pileus} from "../Pileus.sol"; 5 | import {IWorldID} from "../interfaces/IWorldID.sol"; 6 | import {ByteHasher} from "../helpers/ByteHasher.sol"; 7 | import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; 8 | 9 | /// @title World ID verifier for Pileus 10 | /// @author pileum.org 11 | /// @notice Verify World ID proofs to issue Pileus tokens 12 | /// @custom:security-contact security@pileum.org 13 | contract WorldIDVerifier { 14 | using ByteHasher for bytes; 15 | 16 | /////////////////////////////////////////////////////////////////////////////// 17 | /// CONFIG STORAGE /// 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | /// @dev The World ID instance that will be used for verifying proofs 21 | IWorldID internal immutable worldId; 22 | 23 | /// @dev The World ID app ID 24 | uint256 internal immutable appIdHash; 25 | 26 | string internal constant actionIdPrefix = "claim-"; 27 | 28 | /// @dev The World ID group ID (always 1) 29 | uint256 internal immutable groupId = 1; 30 | 31 | /// @dev The Pileus token distributed to participants 32 | Pileus public immutable token; 33 | 34 | /// @dev An event that is emitted when a user successfully verifies with World ID 35 | event Verified(address indexed account, uint256 indexed tokenId, uint32 epoch); 36 | 37 | /// @param _worldId The WorldID router that will verify the proof 38 | /// @param _appId The World ID app ID 39 | /// @param _token The Pileus token distributed to participants 40 | constructor(IWorldID _worldId, string memory _appId, Pileus _token) { 41 | worldId = _worldId; 42 | appIdHash = abi.encodePacked(_appId).hashToField(); 43 | token = _token; 44 | } 45 | 46 | /////////////////////////////////////////////////////////////////////////////// 47 | /// CLAIM LOGIC /// 48 | ////////////////////////////////////////////////////////////////////////////// 49 | 50 | /// @param signal user's wallet address 51 | /// @param root The root of the Merkle tree 52 | /// @param nullifierHash The nullifier hash for this proof, preventing double signaling 53 | /// @param proof The zero-knowledge proof that demonstrates the claimer is registered with World ID 54 | function claimToken(bool nextEpoch, address signal, uint256 root, uint256 nullifierHash, uint256[8] calldata proof) 55 | public 56 | { 57 | uint32 epoch; 58 | uint48 mintBlock; 59 | if (nextEpoch) { 60 | epoch = token.nextEpoch(); 61 | mintBlock = uint48(epoch * token.EPOCH_DURATION()); // start block of next epoch 62 | } else { 63 | epoch = token.currEpoch(); 64 | mintBlock = token.clock(); 65 | } 66 | string memory actionId = string(abi.encodePacked(actionIdPrefix, Strings.toString(epoch))); 67 | uint256 externalNullifier = abi.encodePacked(appIdHash, actionId).hashToField(); 68 | // We now verify the provided proof is valid and the user is verified by World ID 69 | worldId.verifyProof( 70 | root, groupId, abi.encodePacked(signal).hashToField(), nullifierHash, externalNullifier, proof 71 | ); 72 | 73 | token.issueToken(signal, nullifierHash, mintBlock); 74 | 75 | emit Verified(signal, nullifierHash, epoch); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/OCO.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.22; 3 | 4 | import {IOCO} from "./interfaces/IOCO.sol"; 5 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | import {ERC20Bridgeable} from "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Bridgeable.sol"; 7 | import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; 8 | 9 | /// @title O=C=O ERC20 token 10 | /// @author pileum.org 11 | /// @notice O=C=O tokens represent CO2e emissions. 12 | /// @dev This contract uses AccessControl for role-based permissions allowing flexible administrative control, 13 | /// as well as ERC20 and ERC20Bridgeable for token and bridge functionality. 14 | /// @custom:security-contact security@pileum.org 15 | contract OCO is IOCO, ERC20, ERC20Bridgeable, AccessControl { 16 | /// @notice Predeployed Superchain Token Bridge address. 17 | address internal constant SUPERCHAIN_TOKEN_BRIDGE = 0x4200000000000000000000000000000000000028; 18 | 19 | /// @notice Role identifier for accounts that are allowed to mint tokens and track burns. 20 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 21 | 22 | /// @notice Error thrown when an unauthorized address attempts to call a restricted function. 23 | error Unauthorized(); 24 | 25 | /// @notice Mapping that tracks the cumulative burned token amounts for each account. 26 | mapping(address account => uint256) private _burned; 27 | 28 | /// @notice Emitted when tokens are burned. 29 | /// @param account The address from which tokens were burned. 30 | /// @param total The cumulative total of tokens burned by the account. 31 | /// @param value The amount of tokens burned in this operation. 32 | event Burn(address indexed account, uint256 total, uint256 value); 33 | 34 | /// @notice Constructor that initializes the token with a name, symbol, and sets the initial admin. 35 | /// @dev Grants DEFAULT_ADMIN_ROLE to the provided defaultAdmin. 36 | /// @param defaultAdmin The address to be set as the initial admin with full access control privileges. 37 | constructor(address defaultAdmin) ERC20("O=C=O", "OCO") { 38 | _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); 39 | } 40 | 41 | /// @notice Mints new tokens to a specified address. 42 | /// @dev Only callable by accounts with the MINTER_ROLE. Uses ERC20 _mint internally. 43 | /// @param to The address receiving the minted tokens. 44 | /// @param amount The number of tokens to mint. 45 | function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { 46 | _mint(to, amount); 47 | } 48 | 49 | /// @notice Manually tracks burned tokens for an account. 50 | /// @dev Updates the internal burn record and emits a Burn event. Only callable by accounts with the MINTER_ROLE. 51 | /// @param to The account whose burn record will be updated. 52 | /// @param amount The number of tokens to add to the burn record. 53 | function trackBurn(address to, uint256 amount) public onlyRole(MINTER_ROLE) { 54 | _trackBurn(to, amount); 55 | } 56 | 57 | /// @notice Burns a specified amount of tokens from the caller's account. 58 | /// @dev Reduces the caller's balance and updates the burn tracking. See {ERC20-_burn}. 59 | /// @param value The amount of tokens to burn. 60 | function burn(uint256 value) public { 61 | _burn(_msgSender(), value); 62 | _trackBurn(_msgSender(), value); 63 | } 64 | 65 | /// @notice Burns a specified amount of tokens from a target account using the caller's allowance. 66 | /// @dev Reduces the target account's balance and the caller's allowance accordingly. 67 | /// See {ERC20-_burn} and {ERC20-allowance}. 68 | /// @param account The account from which tokens will be burned. 69 | /// @param value The amount of tokens to burn. 70 | function burnFrom(address account, uint256 value) public { 71 | _spendAllowance(account, _msgSender(), value); 72 | _burn(account, value); 73 | _trackBurn(account, value); 74 | } 75 | 76 | /// @notice Internal function to update the burn record for an account. 77 | /// @dev Increments the burned token count for the account and emits a Burn event. 78 | /// @param account The account whose burn record is being updated. 79 | /// @param value The amount of tokens that were burned. 80 | function _trackBurn(address account, uint256 value) internal { 81 | _burned[account] += value; 82 | emit Burn(account, _burned[account], value); 83 | } 84 | 85 | /// @notice Retrieves the total burned tokens recorded for a specific account. 86 | /// @param account The address for which the burned token total is queried. 87 | /// @return The cumulative burned token count for the account. 88 | function burnedBalanceOf(address account) public view returns (uint256) { 89 | return _burned[account]; 90 | } 91 | 92 | /// @notice Verifies that the caller is the designated Superchain Token Bridge. 93 | /// @dev Reverts with {Unauthorized} if the caller is not the predeployed Superchain Token Bridge. 94 | /// This function is part of the ERC20Bridgeable interface. 95 | /// @param caller The address to be validated as the token bridge. 96 | function _checkTokenBridge(address caller) internal pure override { 97 | if (caller != SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized(); 98 | } 99 | 100 | /// @notice Indicates which interfaces are supported by this contract. 101 | /// @dev Combines support for both ERC20Bridgeable and AccessControl interfaces. 102 | /// @param interfaceId The interface identifier, as specified in ERC165. 103 | /// @return A boolean indicating whether the interface is supported. 104 | function supportsInterface(bytes4 interfaceId) 105 | public 106 | view 107 | override(ERC20Bridgeable, AccessControl) 108 | returns (bool) 109 | { 110 | return super.supportsInterface(interfaceId); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Votes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v5.1.0) (governance/utils/Votes.sol) 3 | // Modified for pileum.org 4 | pragma solidity ^0.8.20; 5 | 6 | import {IERC5805} from "@openzeppelin/contracts/interfaces/IERC5805.sol"; 7 | import {Context} from "@openzeppelin/contracts/utils/Context.sol"; 8 | import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol"; 9 | import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; 10 | import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol"; 11 | import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; 12 | import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 13 | import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; 14 | 15 | /** 16 | * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be 17 | * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of 18 | * "representative" that will pool delegated voting units from different accounts and can then use it to vote in 19 | * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to 20 | * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. 21 | * 22 | * This contract is often combined with a token contract such that voting units correspond to token units. For an 23 | * example, see {ERC721Votes}. 24 | * 25 | * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed 26 | * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the 27 | * cost of this history tracking optional. 28 | * 29 | * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return 30 | * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the 31 | * previous example, it would be included in {ERC721-_update}). 32 | */ 33 | abstract contract Votes is Context, EIP712, Nonces, IERC5805 { 34 | using Checkpoints for Checkpoints.Trace208; 35 | 36 | bytes32 private constant DELEGATION_TYPEHASH = 37 | keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); 38 | 39 | mapping(address account => address) private _delegatee; 40 | 41 | //struct delegateEpoch: {uint48 epochStart, uint48 epochEnd, uint160 delegateAddress} 42 | mapping(uint256 delegateEpoch => Checkpoints.Trace208) private _delegateCheckpoints; 43 | 44 | mapping(uint32 epoch => Checkpoints.Trace208) private _totalCheckpoints; 45 | 46 | /** 47 | * @dev The clock was incorrectly modified. 48 | */ 49 | error ERC6372InconsistentClock(); 50 | 51 | /** 52 | * @dev Lookup to future votes is not available. 53 | */ 54 | error ERC5805FutureLookup(uint256 timepoint, uint48 clock); 55 | 56 | /** 57 | * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based 58 | * checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match. 59 | */ 60 | function clock() public view virtual returns (uint48) { 61 | return Time.blockNumber(); 62 | } 63 | 64 | function epoch(uint48 timepoint) public view virtual returns (uint32); 65 | 66 | function currEpoch() public view virtual returns (uint32); 67 | 68 | function epochAddress(address account, uint48 timepoint) internal view virtual returns (uint256); 69 | 70 | function epochIndexAddress(address account, uint32 epochIndex) internal pure virtual returns (uint256); 71 | 72 | /** 73 | * @dev Machine-readable description of the clock as specified in ERC-6372. 74 | */ 75 | // solhint-disable-next-line func-name-mixedcase 76 | function CLOCK_MODE() public view virtual returns (string memory) { 77 | // Check that the clock was not modified 78 | if (clock() != Time.blockNumber()) { 79 | revert ERC6372InconsistentClock(); 80 | } 81 | return "mode=blocknumber&from=default"; 82 | } 83 | 84 | /** 85 | * @dev Returns the current amount of votes that `account` has. 86 | */ 87 | function getVotes(address account) public view virtual returns (uint256) { 88 | return _delegateCheckpoints[epochIndexAddress(account, currEpoch())].latest(); 89 | } 90 | 91 | /** 92 | * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is 93 | * configured to use block numbers, this will return the value at the end of the corresponding block. 94 | * 95 | * Requirements: 96 | * 97 | * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. 98 | */ 99 | function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) { 100 | uint48 currentTimepoint = clock(); 101 | if (timepoint >= currentTimepoint) { 102 | revert ERC5805FutureLookup(timepoint, currentTimepoint); 103 | } 104 | return _delegateCheckpoints[epochAddress(account, SafeCast.toUint48(timepoint))].upperLookupRecent( 105 | SafeCast.toUint48(timepoint) 106 | ); 107 | } 108 | 109 | /** 110 | * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is 111 | * configured to use block numbers, this will return the value at the end of the corresponding block. 112 | * 113 | * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. 114 | * Votes that have not been delegated are still part of total supply, even though they would not participate in a 115 | * vote. 116 | * 117 | * Requirements: 118 | * 119 | * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. 120 | */ 121 | function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) { 122 | uint48 currentTimepoint = clock(); 123 | if (timepoint >= currentTimepoint) { 124 | revert ERC5805FutureLookup(timepoint, currentTimepoint); 125 | } 126 | return _totalCheckpoints[epoch(SafeCast.toUint48(timepoint))].upperLookupRecent(SafeCast.toUint48(timepoint)); 127 | } 128 | 129 | /** 130 | * @dev Returns the current total supply of votes. 131 | */ 132 | function _getTotalSupply() internal view virtual returns (uint256) { 133 | return _totalCheckpoints[currEpoch()].latest(); 134 | } 135 | 136 | /** 137 | * @dev Returns the delegate that `account` has chosen. 138 | */ 139 | function delegates(address account) public view virtual returns (address) { 140 | return _delegatee[account]; 141 | } 142 | 143 | /** 144 | * @dev Delegates votes from the sender to `delegatee`. 145 | */ 146 | function delegate(address delegatee) public virtual { 147 | address account = _msgSender(); 148 | _delegate(account, delegatee); 149 | } 150 | 151 | /** 152 | * @dev Delegates votes from signer to `delegatee`. 153 | */ 154 | function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) 155 | public 156 | virtual 157 | { 158 | if (block.timestamp > expiry) { 159 | revert VotesExpiredSignature(expiry); 160 | } 161 | address signer = ECDSA.recover( 162 | _hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))), v, r, s 163 | ); 164 | _useCheckedNonce(signer, nonce); 165 | _delegate(signer, delegatee); 166 | } 167 | 168 | /** 169 | * @dev Delegate all of `account`'s voting units to `delegatee`. 170 | * 171 | * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. 172 | */ 173 | function _delegate(address account, address delegatee) internal virtual { 174 | address oldDelegate = delegates(account); 175 | _delegatee[account] = delegatee; 176 | 177 | emit DelegateChanged(account, oldDelegate, delegatee); 178 | _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account), currEpoch()); 179 | } 180 | 181 | /** 182 | * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` 183 | * should be zero. Total supply of voting units will be adjusted with mints and burns. 184 | */ 185 | function _transferVotingUnits(address from, address to, uint256 amount, uint32 epochIndex) internal virtual { 186 | if (from == address(0)) { 187 | _push(_totalCheckpoints[epochIndex], _add, SafeCast.toUint208(amount)); 188 | } 189 | if (to == address(0)) { 190 | _push(_totalCheckpoints[epochIndex], _subtract, SafeCast.toUint208(amount)); 191 | } 192 | _moveDelegateVotes(delegates(from), delegates(to), amount, epochIndex); 193 | } 194 | 195 | /** 196 | * @dev Moves delegated votes from one delegate to another. 197 | */ 198 | function _moveDelegateVotes(address from, address to, uint256 amount, uint32 epochIndex) internal virtual { 199 | if (from != to && amount > 0) { 200 | if (from != address(0)) { 201 | (uint256 oldValue, uint256 newValue) = _push( 202 | _delegateCheckpoints[epochIndexAddress(from, epochIndex)], _subtract, SafeCast.toUint208(amount) 203 | ); 204 | emit DelegateVotesChanged(from, oldValue, newValue); 205 | } 206 | if (to != address(0)) { 207 | (uint256 oldValue, uint256 newValue) = 208 | _push(_delegateCheckpoints[epochIndexAddress(to, epochIndex)], _add, SafeCast.toUint208(amount)); 209 | emit DelegateVotesChanged(to, oldValue, newValue); 210 | } 211 | } 212 | } 213 | 214 | /** 215 | * @dev Get number of checkpoints for `account`. 216 | */ 217 | function _numCheckpoints(address account) internal view virtual returns (uint32) { 218 | return SafeCast.toUint32(_delegateCheckpoints[epochIndexAddress(account, currEpoch())].length()); 219 | } 220 | 221 | /** 222 | * @dev Get the `pos`-th checkpoint for `account`. 223 | */ 224 | function _checkpoints(address account, uint32 pos) 225 | internal 226 | view 227 | virtual 228 | returns (Checkpoints.Checkpoint208 memory) 229 | { 230 | return _delegateCheckpoints[epochIndexAddress(account, currEpoch())].at(pos); 231 | } 232 | 233 | function _push( 234 | Checkpoints.Trace208 storage store, 235 | function(uint208, uint208) view returns (uint208) op, 236 | uint208 delta 237 | ) private returns (uint208 oldValue, uint208 newValue) { 238 | return store.push(clock(), op(store.latest(), delta)); 239 | } 240 | 241 | function _add(uint208 a, uint208 b) private pure returns (uint208) { 242 | return a + b; 243 | } 244 | 245 | function _subtract(uint208 a, uint208 b) private pure returns (uint208) { 246 | return a - b; 247 | } 248 | 249 | /** 250 | * @dev Must return the voting units held by an account. 251 | */ 252 | function _getVotingUnits(address) internal view virtual returns (uint256); 253 | } 254 | -------------------------------------------------------------------------------- /src/Pileus.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import {ERC721} from "./ERC721.sol"; 5 | import {ERC721Votes} from "./ERC721Votes.sol"; 6 | import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; 7 | import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; 8 | import {Base64} from "@openzeppelin/contracts/utils/Base64.sol"; 9 | import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; 10 | 11 | /// @title Pileus ERC721 token 12 | /// @author pileum.org 13 | /// @notice One Pileus token per person 14 | /// @custom:security-contact security@pileum.org 15 | contract Pileus is AccessControl, EIP712, ERC721Votes { 16 | using Strings for uint256; 17 | 18 | string private constant TOKEN_NAME = "Pileus"; 19 | string private constant TOKEN_SYM = "PIL"; 20 | string private constant TOKEN_VER = "1"; 21 | string private constant TOKEN_DESC = "Servos ad pileum vocare"; 22 | string private constant TOKEN_BASE_URI = "https://app.pileum.org/pileus"; 23 | bytes32 public constant VERIFIER_ROLE = keccak256("VERIFIER_ROLE"); 24 | 25 | /// @notice The average block production time in seconds. 26 | uint48 public immutable blockTime; 27 | 28 | /** 29 | * @notice Struct for minting parameters. 30 | * @param to Address of the token recipient. 31 | * @param tokenId Identifier of the token. 32 | * @param mintBlock Block number for minting. 33 | */ 34 | struct MintParams { 35 | address to; 36 | uint256 tokenId; 37 | uint48 mintBlock; 38 | } 39 | 40 | /** 41 | * @notice Initializes the Pileus contract. 42 | * @dev Sets up ERC721Votes with the given epoch duration, initializes ERC721 and EIP712. 43 | * @param defaultAdmin Address granted the DEFAULT_ADMIN_ROLE. 44 | * @param epochDuration_ Duration of each epoch used by ERC721Votes. 45 | */ 46 | constructor(address defaultAdmin, uint48 epochDuration_, uint48 blockTime_) 47 | ERC721Votes(epochDuration_) 48 | ERC721(TOKEN_NAME, TOKEN_SYM) 49 | EIP712(TOKEN_NAME, TOKEN_VER) 50 | { 51 | _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); 52 | blockTime = blockTime_; 53 | } 54 | 55 | // ==TOKEN ISSUANCE== 56 | 57 | /** 58 | * @notice Issues a token to a specified address. 59 | * @dev Only accounts with the VERIFIER_ROLE can call this function. 60 | * If the token already exists and is owned by a different address, a safe transfer is performed. 61 | * @param to Address of the token recipient. 62 | * @param tokenId Identifier of the token to be issued. 63 | */ 64 | function issueToken(address to, uint256 tokenId) external onlyRole(VERIFIER_ROLE) { 65 | _issueToken(to, tokenId, clock()); 66 | } 67 | 68 | /** 69 | * @notice Issues a token to a specified address with a specific mint block. 70 | * @dev Only accounts with the VERIFIER_ROLE can call this function. 71 | * Allows explicit specification of the mint block. 72 | * @param to Address of the token recipient. 73 | * @param tokenId Identifier of the token to be issued. 74 | * @param mintBlock Block number to record the minting time. 75 | */ 76 | function issueToken(address to, uint256 tokenId, uint48 mintBlock) external onlyRole(VERIFIER_ROLE) { 77 | _issueToken(to, tokenId, mintBlock); 78 | } 79 | 80 | /** 81 | * @notice Batch issues multiple tokens. 82 | * @dev Only accounts with the VERIFIER_ROLE can call this function. 83 | * Iterates over an array of MintParams and issues tokens accordingly. 84 | * @param tokens Array of MintParams containing recipient addresses, token IDs, and mint blocks. 85 | */ 86 | function issueTokens(MintParams[] calldata tokens) external onlyRole(VERIFIER_ROLE) { 87 | for (uint256 i = 0; i < tokens.length; i++) { 88 | _issueToken(tokens[i].to, tokens[i].tokenId, tokens[i].mintBlock); 89 | } 90 | } 91 | 92 | /** 93 | * @notice Internal function to issue or transfer a token. 94 | * @dev If the token exists and is owned by a different address, performs a safe transfer. 95 | * If the token does not exist, mints it and sets the delegation to the recipient. 96 | * @param to Address of the token recipient. 97 | * @param tokenId Identifier of the token. 98 | * @param mintBlock Block number to record the minting time. 99 | */ 100 | function _issueToken(address to, uint256 tokenId, uint48 mintBlock) internal { 101 | (address from, uint48 prevMintBlock) = propsOf(tokenId); 102 | if (from != address(0)) { 103 | if (from != to) { 104 | _safeTransfer(from, to, tokenId, prevMintBlock); 105 | } 106 | } else { 107 | _safeMint(to, tokenId, mintBlock); 108 | if (delegates(to) == address(0)) { 109 | // Delegation persists across epochs 110 | _delegate(to, to); 111 | } 112 | } 113 | } 114 | 115 | // ==VIEWS== 116 | 117 | /** 118 | * @notice Returns the base URI for token metadata. 119 | * @dev Overrides the internal ERC721 _baseURI function. 120 | * @return Base URI string. 121 | */ 122 | function _baseURI() internal pure override returns (string memory) { 123 | return TOKEN_BASE_URI; 124 | } 125 | 126 | /** 127 | * @notice Retrieves the token ID associated with an owner in the current epoch. 128 | * @param owner Address to query. 129 | * @return Token ID owned by the provided address. 130 | */ 131 | function getToken(address owner) external view returns (uint256) { 132 | return super.getToken(owner, currEpoch()); 133 | } 134 | 135 | /** 136 | * @notice Retrieves token attributes. 137 | * @dev Returns the mint block and epoch end block for a given token. 138 | * @param tokenId Identifier of the token. 139 | * @return mintBlock Block number when the token was minted. 140 | * @return end Block number when the current epoch ends. 141 | */ 142 | function getAttributes(uint256 tokenId) public view returns (uint48, uint48) { 143 | (, uint48 mintBlock) = propsOf(tokenId); 144 | (, uint48 end) = epochRange(mintBlock); 145 | return (mintBlock, end); 146 | } 147 | 148 | /** 149 | * @notice Approximates a Unix timestamp for a given target block number. 150 | * @dev The function uses the current block number (`block.number`) and timestamp (`block.timestamp`) 151 | * as the baseline. It calculates the difference between the target block and the current block, 152 | * then adds or subtracts the product of this difference and the average block time. 153 | * This method only provides an approximate result as block times can vary. 154 | * @param targetBlockNumber The block number for which to estimate the timestamp. 155 | * @return estimatedTimestamp The approximated Unix timestamp for the target block. 156 | */ 157 | function approximateTimestamp(uint256 targetBlockNumber) public view returns (uint256 estimatedTimestamp) { 158 | uint256 currentBlock = block.number; 159 | uint256 currentTimestamp = block.timestamp; 160 | 161 | if (targetBlockNumber >= currentBlock) { 162 | estimatedTimestamp = currentTimestamp + ((targetBlockNumber - currentBlock) * uint256(blockTime)); 163 | } else { 164 | estimatedTimestamp = currentTimestamp - ((currentBlock - targetBlockNumber) * uint256(blockTime)); 165 | } 166 | } 167 | 168 | /** 169 | * @notice Generates the token URI with metadata for a given token ID. 170 | * @dev Constructs a data URI containing a base64 encoded JSON object with token metadata. 171 | * @param tokenId Identifier of the token. 172 | * @return Token URI string. 173 | */ 174 | function tokenURI(uint256 tokenId) public view override returns (string memory) { 175 | (uint256 creationBlk, uint256 expirationBlk) = getAttributes(tokenId); 176 | uint256 creationTS = approximateTimestamp(creationBlk); 177 | uint256 expirationTS = approximateTimestamp(expirationBlk); 178 | bytes memory attributes = abi.encodePacked( 179 | '[{"display_type": "date",', 180 | '"trait_type": "creation", ', 181 | '"value": ', 182 | creationTS.toString(), 183 | "},{", 184 | '"display_type": "number",', 185 | '"trait_type": "creation_block", ', 186 | '"value": ', 187 | creationBlk.toString(), 188 | "},{", 189 | '"display_type": "date",', 190 | '"trait_type": "expiration", ', 191 | '"value": ', 192 | expirationTS.toString(), 193 | "},{", 194 | '"display_type": "number",', 195 | '"trait_type": "expiration_block", ', 196 | '"value": ', 197 | expirationBlk.toString(), 198 | "}]" 199 | ); 200 | bytes memory dataURI = abi.encodePacked( 201 | "{", 202 | '"name": "', 203 | TOKEN_NAME, 204 | " #", 205 | tokenId.toString(), 206 | '", "description": "', 207 | TOKEN_DESC, 208 | '", "image": "', 209 | imageData(tokenId), 210 | '", "background_color": "424242', 211 | '", "external_url": "', 212 | externalUrl(tokenId), 213 | '", "attributes": ', 214 | attributes, 215 | "}" 216 | ); 217 | return string(abi.encodePacked("data:application/json;base64,", Base64.encode(dataURI))); 218 | } 219 | 220 | /** 221 | * @notice Generates an external URL for a token. 222 | * @dev Constructs a URL with query parameters based on token attributes and the current block number. 223 | * @param tokenId Identifier of the token. 224 | * @return External URL string. 225 | */ 226 | function externalUrl(uint256 tokenId) public view returns (string memory) { 227 | (uint256 creationBlk, uint256 expirationBlk) = getAttributes(tokenId); 228 | string memory baseURI = _baseURI(); 229 | bytes memory url = abi.encodePacked( 230 | baseURI, 231 | "?id=", 232 | tokenId.toString(), 233 | "&c=", 234 | creationBlk.toString(), 235 | "&e=", 236 | expirationBlk.toString(), 237 | "&b=", 238 | block.number.toString(), 239 | "&ts=", 240 | block.timestamp.toString() 241 | ); 242 | return bytes(baseURI).length > 0 ? string(url) : ""; 243 | } 244 | 245 | /** 246 | * @notice Generates a base64 encoded SVG image for a token. 247 | * @dev Uses tokenId to determine the colors for the SVG polygons. 248 | * @param tokenId Identifier of the token. 249 | * @return Base64 encoded SVG image as a data URI. 250 | */ 251 | function imageData(uint256 tokenId) private pure returns (string memory) { 252 | bytes7[16] memory palettes = [ 253 | bytes7("#EAF0B5"), 254 | "#DDECBF", 255 | "#D0E7CA", 256 | "#B5DDD8", 257 | "#A8D8DC", 258 | "#81C4E7", 259 | "#7BBCE7", 260 | "#7EB2E4", 261 | "#88A5DD", 262 | "#9398D2", 263 | "#9B8AC4", 264 | "#9A709E", 265 | "#906388", 266 | "#805770", 267 | "#684957", 268 | "#46353A" 269 | ]; 270 | string[16] memory points = [ 271 | string("0 115.47 "), 272 | "16.67 86.6 ", 273 | "50 144.34 ", 274 | "50 28.87 ", 275 | "50 86.6 ", 276 | "83.33 86.6 ", 277 | "100 0 ", 278 | "100 115.47 ", 279 | "100 57.73 ", 280 | "116.67 144.34 ", 281 | "116.67 28.87 ", 282 | "150 144.34 ", 283 | "150 28.87 ", 284 | "150 86.6 ", 285 | "183.33 144.34 ", 286 | "200 115.47 " 287 | ]; 288 | uint8[3][16] memory polygons = [ 289 | [15, 13, 14], 290 | [14, 11, 13], 291 | [9, 13, 11], 292 | [13, 7, 9], 293 | [1, 0, 2], 294 | [1, 4, 2], 295 | [2, 5, 4], 296 | [2, 7, 5], 297 | [5, 13, 7], 298 | [5, 8, 13], 299 | [4, 5, 3], 300 | [8, 3, 5], 301 | [8, 10, 3], 302 | [13, 12, 10], 303 | [8, 10, 13], 304 | [3, 6, 10] 305 | ]; 306 | bytes memory svg = abi.encodePacked( 307 | '' 308 | ); 309 | for (uint8 p = 0; p < polygons.length; p++) { 310 | svg = abi.encodePacked( 311 | svg, 312 | '' 320 | ); 321 | } 322 | svg = abi.encodePacked(svg, ""); 323 | return string(abi.encodePacked("data:image/svg+xml;base64,", Base64.encode(svg))); 324 | } 325 | 326 | /** 327 | * @notice Returns the contract-level metadata URI. 328 | * @dev Provides contract metadata as a data URI containing a base64 encoded JSON object. 329 | * @return Contract URI string. 330 | */ 331 | function contractURI() public pure returns (string memory) { 332 | bytes memory json = abi.encodePacked( 333 | "data:application/json;utf8,", 334 | "{", 335 | '"name": "', 336 | TOKEN_NAME, 337 | '", "description": "', 338 | TOKEN_DESC, 339 | '", "image_data": "', 340 | imageData(0xB67A9854CDEF3210), 341 | '", "external_url": "', 342 | _baseURI(), 343 | '"}' 344 | ); 345 | return string(json); 346 | } 347 | 348 | /** 349 | * @notice Checks if the contract supports a given interface. 350 | * @dev Implements ERC165 interface detection. 351 | * @param interfaceId The interface identifier. 352 | * @return True if the contract implements the requested interface, false otherwise. 353 | */ 354 | function supportsInterface(bytes4 interfaceId) public view override(ERC721, AccessControl) returns (bool) { 355 | return super.supportsInterface(interfaceId); 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/ERC721.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/ERC721.sol) 3 | // Modified for pileum.org 4 | pragma solidity ^0.8.20; 5 | 6 | import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 7 | import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; 8 | import {ERC721Utils} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol"; 9 | import {Context} from "@openzeppelin/contracts/utils/Context.sol"; 10 | import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; 11 | import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; 12 | import {IERC165, ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; 13 | import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; 14 | 15 | /** 16 | * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC-721] Non-Fungible Token Standard, including 17 | * the Metadata extension, but not including the Enumerable extension, which is available separately as 18 | * {ERC721Enumerable}. 19 | */ 20 | abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { 21 | using Strings for uint256; 22 | 23 | // Token name 24 | string private _name; 25 | 26 | // Token symbol 27 | string private _symbol; 28 | 29 | mapping(uint256 tokenId => uint256 ownerProps) private _owners; //struct ownerProps: {uint48 mintBlock, uint48 unused, uint160 ownerAddress} 30 | 31 | mapping(uint256 owner => uint256 tokenId) private _tokens; //struct owner: {uint48 epochStart, uint48 epochEnd, uint160 ownerAddress} 32 | 33 | mapping(uint256 tokenId => address) private _tokenApprovals; 34 | 35 | mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; 36 | 37 | function epochAddress(address account, uint48 timepoint) internal view virtual returns (uint256); 38 | 39 | function epochIndexAddress(address account, uint32 epochIndex) internal pure virtual returns (uint256) { 40 | return (uint256(epochIndex) << 160) | uint256(uint160(account)); 41 | } 42 | 43 | error ERC721ReceiverAlreadyOwns(address receiver); 44 | 45 | /** 46 | * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. 47 | */ 48 | constructor(string memory name_, string memory symbol_) { 49 | _name = name_; 50 | _symbol = symbol_; 51 | } 52 | 53 | /** 54 | * @dev See {IERC165-supportsInterface}. 55 | */ 56 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { 57 | return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId 58 | || super.supportsInterface(interfaceId); 59 | } 60 | 61 | /** 62 | * @dev See {IERC721-balanceOf}. 63 | */ 64 | function balanceOf(address owner, uint32 epochIndex) public view virtual returns (uint256) { 65 | if (owner == address(0)) { 66 | revert ERC721InvalidOwner(address(0)); 67 | } 68 | return (_tokens[epochIndexAddress(owner, epochIndex)] == 0 ? 0 : 1); 69 | } 70 | 71 | function getToken(address owner, uint32 epochIndex) public view virtual returns (uint256) { 72 | return _tokens[epochIndexAddress(owner, epochIndex)]; 73 | } 74 | 75 | /** 76 | * @dev See {IERC721-ownerOf}. 77 | */ 78 | function ownerOf(uint256 tokenId) public view virtual returns (address) { 79 | return _requireOwned(tokenId); 80 | } 81 | 82 | function propsOf(uint256 tokenId) public view virtual returns (address, uint48) { 83 | uint256 props = _owners[tokenId]; 84 | address owner = address(uint160(props)); 85 | uint48 mintDate = uint48(props >> 208); 86 | return (owner, mintDate); 87 | } 88 | 89 | /** 90 | * @dev See {IERC721Metadata-name}. 91 | */ 92 | function name() public view virtual returns (string memory) { 93 | return _name; 94 | } 95 | 96 | /** 97 | * @dev See {IERC721Metadata-symbol}. 98 | */ 99 | function symbol() public view virtual returns (string memory) { 100 | return _symbol; 101 | } 102 | 103 | /** 104 | * @dev See {IERC721Metadata-tokenURI}. 105 | */ 106 | function tokenURI(uint256 tokenId) public view virtual returns (string memory) { 107 | _requireOwned(tokenId); 108 | 109 | string memory baseURI = _baseURI(); 110 | return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : ""; 111 | } 112 | 113 | /** 114 | * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each 115 | * token will be the concatenation of the `baseURI` and the `tokenId`. Empty 116 | * by default, can be overridden in child contracts. 117 | */ 118 | function _baseURI() internal view virtual returns (string memory) { 119 | return ""; 120 | } 121 | 122 | /** 123 | * @dev See {IERC721-approve}. 124 | */ 125 | function approve(address to, uint256 tokenId) public virtual { 126 | _approve(to, tokenId, _msgSender()); 127 | } 128 | 129 | /** 130 | * @dev See {IERC721-getApproved}. 131 | */ 132 | function getApproved(uint256 tokenId) public view virtual returns (address) { 133 | _requireOwned(tokenId); 134 | 135 | return _getApproved(tokenId); 136 | } 137 | 138 | /** 139 | * @dev See {IERC721-setApprovalForAll}. 140 | */ 141 | function setApprovalForAll(address operator, bool approved) public virtual { 142 | _setApprovalForAll(_msgSender(), operator, approved); 143 | } 144 | 145 | /** 146 | * @dev See {IERC721-isApprovedForAll}. 147 | */ 148 | function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { 149 | return _operatorApprovals[owner][operator]; 150 | } 151 | 152 | /** 153 | * @dev See {IERC721-transferFrom}. 154 | */ 155 | function transferFrom(address from, address to, uint256 tokenId) public virtual { 156 | if (to == address(0)) { 157 | revert ERC721InvalidReceiver(address(0)); 158 | } 159 | // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists 160 | // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. 161 | (, uint48 mintBlock) = propsOf(tokenId); //transfer doesn't change mintBlock 162 | address previousOwner = _update(to, tokenId, _msgSender(), mintBlock); 163 | if (previousOwner != from) { 164 | revert ERC721IncorrectOwner(from, tokenId, previousOwner); 165 | } 166 | } 167 | 168 | /** 169 | * @dev See {IERC721-safeTransferFrom}. 170 | */ 171 | function safeTransferFrom(address from, address to, uint256 tokenId) public { 172 | safeTransferFrom(from, to, tokenId, ""); 173 | } 174 | 175 | /** 176 | * @dev See {IERC721-safeTransferFrom}. 177 | */ 178 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { 179 | transferFrom(from, to, tokenId); 180 | ERC721Utils.checkOnERC721Received(_msgSender(), from, to, tokenId, data); 181 | } 182 | 183 | /** 184 | * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist 185 | * 186 | * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the 187 | * core ERC-721 logic MUST be matched with the use of {_increaseBalance} to keep balances 188 | * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by 189 | * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`. 190 | */ 191 | function _ownerOf(uint256 tokenId) internal view virtual returns (address) { 192 | return address(uint160(_owners[tokenId])); 193 | } 194 | 195 | /** 196 | * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. 197 | */ 198 | function _getApproved(uint256 tokenId) internal view virtual returns (address) { 199 | return _tokenApprovals[tokenId]; 200 | } 201 | 202 | /** 203 | * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in 204 | * particular (ignoring whether it is owned by `owner`). 205 | * 206 | * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this 207 | * assumption. 208 | */ 209 | function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) { 210 | return spender != address(0) 211 | && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender); 212 | } 213 | 214 | /** 215 | * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. 216 | * Reverts if: 217 | * - `spender` does not have approval from `owner` for `tokenId`. 218 | * - `spender` does not have approval to manage all of `owner`'s assets. 219 | * 220 | * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this 221 | * assumption. 222 | */ 223 | function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual { 224 | if (!_isAuthorized(owner, spender, tokenId)) { 225 | if (owner == address(0)) { 226 | revert ERC721NonexistentToken(tokenId); 227 | } else { 228 | revert ERC721InsufficientApproval(spender, tokenId); 229 | } 230 | } 231 | } 232 | 233 | /** 234 | * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner 235 | * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. 236 | * 237 | * The `auth` argument is optional. If the value passed is non 0, then this function will check that 238 | * `auth` is either the owner of the token, or approved to operate on the token (by the owner). 239 | * 240 | * Emits a {Transfer} event. 241 | * 242 | * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}. 243 | */ 244 | function _update(address to, uint256 tokenId, address auth, uint48 mintBlock) internal virtual returns (address) { 245 | address from = _ownerOf(tokenId); 246 | 247 | // Perform (optional) operator check 248 | if (auth != address(0)) { 249 | _checkAuthorized(from, auth, tokenId); 250 | } 251 | 252 | // Execute the update 253 | if (from != address(0)) { 254 | // Clear approval. No need to re-authorize or emit the Approval event 255 | _approve(address(0), tokenId, address(0), false); 256 | 257 | unchecked { 258 | _tokens[epochAddress(from, mintBlock)] = 0; 259 | } 260 | } 261 | 262 | if (to != address(0)) { 263 | uint256 epochTo = epochAddress(to, mintBlock); 264 | if (_tokens[epochTo] > 0) { 265 | revert ERC721ReceiverAlreadyOwns(to); 266 | } 267 | unchecked { 268 | _tokens[epochTo] = tokenId; 269 | } 270 | } else { 271 | //burn 272 | mintBlock = 0; 273 | } 274 | 275 | _owners[tokenId] = (uint256(mintBlock) << 208) | uint256(uint160(to)); 276 | 277 | emit Transfer(from, to, tokenId); 278 | 279 | return from; 280 | } 281 | 282 | /** 283 | * @dev Mints `tokenId` and transfers it to `to`. 284 | * 285 | * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible 286 | * 287 | * Requirements: 288 | * 289 | * - `tokenId` must not exist. 290 | * - `to` cannot be the zero address. 291 | * 292 | * Emits a {Transfer} event. 293 | */ 294 | function _mint(address to, uint256 tokenId, uint48 timepoint) internal { 295 | if (to == address(0)) { 296 | revert ERC721InvalidReceiver(address(0)); 297 | } 298 | address previousOwner = _update(to, tokenId, address(0), timepoint); 299 | if (previousOwner != address(0)) { 300 | revert ERC721InvalidSender(address(0)); 301 | } 302 | } 303 | 304 | /** 305 | * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. 306 | * 307 | * Requirements: 308 | * 309 | * - `tokenId` must not exist. 310 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 311 | * 312 | * Emits a {Transfer} event. 313 | */ 314 | function _safeMint(address to, uint256 tokenId, uint48 timepoint) internal { 315 | _safeMint(to, tokenId, "", timepoint); 316 | } 317 | 318 | /** 319 | * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is 320 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 321 | */ 322 | function _safeMint(address to, uint256 tokenId, bytes memory data, uint48 timepoint) internal virtual { 323 | _mint(to, tokenId, timepoint); 324 | ERC721Utils.checkOnERC721Received(_msgSender(), address(0), to, tokenId, data); 325 | } 326 | 327 | /** 328 | * @dev Transfers `tokenId` from `from` to `to`. 329 | * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. 330 | * 331 | * Requirements: 332 | * 333 | * - `to` cannot be the zero address. 334 | * - `tokenId` token must be owned by `from`. 335 | * 336 | * Emits a {Transfer} event. 337 | */ 338 | function _transfer(address from, address to, uint256 tokenId, uint48 timepoint) internal { 339 | if (to == address(0)) { 340 | revert ERC721InvalidReceiver(address(0)); 341 | } 342 | address previousOwner = _update(to, tokenId, address(0), timepoint); 343 | if (previousOwner == address(0)) { 344 | revert ERC721NonexistentToken(tokenId); 345 | } else if (previousOwner != from) { 346 | revert ERC721IncorrectOwner(from, tokenId, previousOwner); 347 | } 348 | } 349 | 350 | /** 351 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients 352 | * are aware of the ERC-721 standard to prevent tokens from being forever locked. 353 | * 354 | * `data` is additional data, it has no specified format and it is sent in call to `to`. 355 | * 356 | * This internal function is like {safeTransferFrom} in the sense that it invokes 357 | * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g. 358 | * implement alternative mechanisms to perform token transfer, such as signature-based. 359 | * 360 | * Requirements: 361 | * 362 | * - `tokenId` token must exist and be owned by `from`. 363 | * - `to` cannot be the zero address. 364 | * - `from` cannot be the zero address. 365 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 366 | * 367 | * Emits a {Transfer} event. 368 | */ 369 | function _safeTransfer(address from, address to, uint256 tokenId, uint48 timepoint) internal { 370 | _safeTransfer(from, to, tokenId, "", timepoint); 371 | } 372 | 373 | /** 374 | * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is 375 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 376 | */ 377 | function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data, uint48 timepoint) 378 | internal 379 | virtual 380 | { 381 | _transfer(from, to, tokenId, timepoint); 382 | ERC721Utils.checkOnERC721Received(_msgSender(), from, to, tokenId, data); 383 | } 384 | 385 | /** 386 | * @dev Approve `to` to operate on `tokenId` 387 | * 388 | * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is 389 | * either the owner of the token, or approved to operate on all tokens held by this owner. 390 | * 391 | * Emits an {Approval} event. 392 | * 393 | * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. 394 | */ 395 | function _approve(address to, uint256 tokenId, address auth) internal { 396 | _approve(to, tokenId, auth, true); 397 | } 398 | 399 | /** 400 | * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not 401 | * emitted in the context of transfers. 402 | */ 403 | function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual { 404 | // Avoid reading the owner unless necessary 405 | if (emitEvent || auth != address(0)) { 406 | address owner = _requireOwned(tokenId); 407 | 408 | // We do not use _isAuthorized because single-token approvals should not be able to call approve 409 | if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) { 410 | revert ERC721InvalidApprover(auth); 411 | } 412 | 413 | if (emitEvent) { 414 | emit Approval(owner, to, tokenId); 415 | } 416 | } 417 | 418 | _tokenApprovals[tokenId] = to; 419 | } 420 | 421 | /** 422 | * @dev Approve `operator` to operate on all of `owner` tokens 423 | * 424 | * Requirements: 425 | * - operator can't be the address zero. 426 | * 427 | * Emits an {ApprovalForAll} event. 428 | */ 429 | function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { 430 | if (operator == address(0)) { 431 | revert ERC721InvalidOperator(operator); 432 | } 433 | _operatorApprovals[owner][operator] = approved; 434 | emit ApprovalForAll(owner, operator, approved); 435 | } 436 | 437 | /** 438 | * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). 439 | * Returns the owner. 440 | * 441 | * Overrides to ownership logic should be done to {_ownerOf}. 442 | */ 443 | function _requireOwned(uint256 tokenId) internal view returns (address) { 444 | address owner = _ownerOf(tokenId); 445 | if (owner == address(0)) { 446 | revert ERC721NonexistentToken(tokenId); 447 | } 448 | return owner; 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /src/TOTC.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 5 | import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; 6 | import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; 7 | import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; 8 | import {IPileus} from "./interfaces/IPileus.sol"; 9 | import {IOCO} from "./interfaces/IOCO.sol"; 10 | 11 | /// @title TOTC Contract 12 | /// @author pileum.org 13 | /// @notice Manages the OCO allowance and trading mechanisms for Pileus owners. 14 | /// @dev OCO tokens can be minted only by this contract. It supports claiming, buying, 15 | /// settling, and withdrawing based on per-epoch rules. 16 | /// @custom:security-contact security@pileum.org 17 | contract TOTC is Ownable, ReentrancyGuard { 18 | // ============================================================= 19 | // EVENTS 20 | // ============================================================= 21 | 22 | /// @notice Emitted when the allowance parameters are updated. 23 | /// @param allowanceSlope The new slope used in allowance calculations. 24 | /// @param allowanceIntercept The new intercept used in allowance calculations. 25 | event AllowanceUpdate(int256 allowanceSlope, int256 allowanceIntercept); 26 | 27 | /// @notice Emitted when a user buys OCO tokens by investing ETH. 28 | /// @param operator The address performing the buy operation. 29 | /// @param epoch The epoch in which the buy is executed. 30 | /// @param valuePerBlock The computed ETH value allocated per block. 31 | /// @param remainder The remaining ETH returned to the user. 32 | event Buy(address indexed operator, uint32 indexed epoch, uint128 valuePerBlock, uint128 remainder); 33 | 34 | /// @notice Emitted when a Pileus owner claims their OCO allowance. 35 | /// @param operator The address initiating the claim. 36 | /// @param tokenId The Pileus token id used for the claim. 37 | /// @param to The recipient address of the minted OCO tokens (or burn indicator if address(0)). 38 | /// @param amount The amount of OCO tokens claimed. 39 | /// @param used The updated claim index after the claim. 40 | event Claim(address indexed operator, uint256 indexed tokenId, address indexed to, uint128 amount, uint128 used); 41 | 42 | /// @notice Emitted when an account settles their invested ETH into OCO tokens. 43 | /// @param operator The address that settled the account. 44 | /// @param value The invested ETH value that was settled. 45 | /// @param amountQ128 The settled OCO token amount in fixed-point Q128. 46 | /// @param duration The number of blocks over which settlement was calculated. 47 | event Settle(address indexed operator, uint128 value, uint256 amountQ128, uint48 duration); 48 | 49 | /// @notice Emitted when a Pileus token owner withdraws proceeds from unclaimed allowance. 50 | /// @param operator The address withdrawing the proceeds. 51 | /// @param amount The amount of OCO allowance withdrawn. 52 | /// @param valueQ128 The corresponding ETH value in fixed-point Q128. 53 | event Withdraw(address indexed operator, uint128 amount, uint256 valueQ128); 54 | 55 | /// @notice Emitted when total balances are updated for an epoch. 56 | /// @param totalSupply Total OCO supply that could be invested. 57 | /// @param supplyClaimed Total OCO supply that has been claimed. 58 | /// @param supplyWithdrawn Total OCO supply that has been withdrawn. 59 | /// @param supplySettled Total OCO supply that has been settled (in Q128 fixed-point). 60 | /// @param valueInvested Total ETH invested. 61 | /// @param valueSettled Total ETH settled. 62 | /// @param valueWithdrawn Total ETH withdrawn (in Q128 fixed-point). 63 | event TotalBalancesUpdate( 64 | uint128 totalSupply, 65 | uint128 supplyClaimed, 66 | uint128 supplyWithdrawn, 67 | uint256 supplySettled, 68 | uint128 valueInvested, 69 | uint128 valueSettled, 70 | uint256 valueWithdrawn 71 | ); 72 | 73 | // ============================================================= 74 | // STORAGE VARIABLES 75 | // ============================================================= 76 | 77 | uint256 internal constant Q128 = 1 << 128; 78 | uint48 private immutable _epochDuration; 79 | IPileus public immutable pileus; 80 | IOCO public immutable oco; 81 | int256 private _allowanceSlope; 82 | int256 private _allowanceIntercept; 83 | 84 | /// @notice Information for an account's buy order. 85 | /// @param valuePerBlk ETH invested per block (in wei). 86 | /// @param lastSettle Last block index at which settlement was executed. 87 | struct AccountInfo { 88 | uint128 valuePerBlk; 89 | uint48 lastSettle; 90 | } 91 | 92 | /// @notice Mapping for account information per epoch. 93 | /// @dev The key is generated via balancesKey(epoch, account). 94 | mapping(uint256 balancesKey => AccountInfo) private _balances; 95 | 96 | /// @notice Tracks the last claimed or withdrawn allowance (in blocks) per Pileus token. 97 | mapping(uint256 tokenId => uint48) private _allowances; 98 | 99 | /// @notice Aggregated totals for allowance and ETH values per epoch. 100 | /// @param supplyClaimed Total claimed OCO tokens. 101 | /// @param supplyWithdrawn Total OCO tokens withdrawn. 102 | /// @param supplySettled Total settled OCO tokens (fixed-point Q128). 103 | /// @param valueInvested Total ETH invested (in wei). 104 | /// @param valueSettled Total ETH settled (in wei). 105 | /// @param valueWithdrawn Total ETH withdrawn (fixed-point Q128). 106 | struct TotalBalances { 107 | uint128 supplyClaimed; 108 | uint128 supplyWithdrawn; 109 | uint256 supplySettled; 110 | uint128 valueInvested; 111 | uint128 valueSettled; 112 | uint256 valueWithdrawn; 113 | } 114 | 115 | /// @notice Mapping of total balances by epoch. 116 | mapping(uint32 epoch => TotalBalances) private _totals; 117 | 118 | // ============================================================= 119 | // CONSTRUCTOR 120 | // ============================================================= 121 | 122 | /// @notice Initializes the TOTC contract. 123 | /// @param initialOwner The address of the initial contract owner. 124 | /// @param _pileus The address of the Pileus ERC721 contract. 125 | /// @param _oco The address of the OCO ERC20 contract. 126 | /// @param allowanceSlope The initial slope for allowance calculation. 127 | /// @param allowanceIntercept The initial intercept for allowance calculation. 128 | constructor(address initialOwner, IPileus _pileus, IOCO _oco, int256 allowanceSlope, int256 allowanceIntercept) 129 | Ownable(initialOwner) 130 | { 131 | pileus = _pileus; 132 | oco = _oco; 133 | _epochDuration = pileus.EPOCH_DURATION(); 134 | _allowanceSlope = allowanceSlope; 135 | _allowanceIntercept = allowanceIntercept; 136 | } 137 | 138 | // ============================================================= 139 | // MUTATING FUNCTIONS 140 | // ============================================================= 141 | 142 | /// @notice Updates the allowance calculation parameters. 143 | /// @param allowanceSlope The new slope for allowance calculation. 144 | /// @param allowanceIntercept The new intercept for allowance calculation. 145 | /// @param blockNumber If non-zero, requires execution at the specified block number. 146 | /// @dev Only the owner can call this function. 147 | function setAllowance(int256 allowanceSlope, int256 allowanceIntercept, uint48 blockNumber) public onlyOwner { 148 | if (blockNumber > 0) { 149 | require(blockNumber == block.number, "Can only be executed at specified block"); 150 | } 151 | _allowanceSlope = allowanceSlope; 152 | _allowanceIntercept = allowanceIntercept; 153 | emit AllowanceUpdate(allowanceSlope, allowanceIntercept); 154 | } 155 | 156 | /// @notice Claims an OCO allowance for a given Pileus token. 157 | /// @param tokenId The Pileus token id. 158 | /// @param to The recipient address to receive OCO tokens (or zero address to track burn). 159 | /// @param duration The duration (in blocks) to claim. 160 | /// @return amount The amount of OCO tokens minted as a result of the claim. 161 | /// @dev Caller must be the token owner or approved. If the token was minted in the current epoch, 162 | /// any pending withdrawal is processed before claiming. 163 | function claim(uint256 tokenId, address to, uint48 duration) public nonReentrant returns (uint128 amount) { 164 | require(duration > 0, "Null claimed duration"); 165 | (address owner, uint48 mintBlock) = pileus.propsOf(tokenId); 166 | require( 167 | msg.sender == owner || pileus.getApproved(tokenId) == msg.sender 168 | || pileus.isApprovedForAll(owner, msg.sender), 169 | "Caller is not token owner nor approved" 170 | ); 171 | uint32 mintEpoch = SafeCast.toUint32(mintBlock / _epochDuration); 172 | require(mintEpoch >= currEpoch(), "Cannot claim past epoch"); 173 | if (mintEpoch == currEpoch()) { 174 | _withdraw(tokenId, mintEpoch); 175 | } 176 | uint48 claimIndex = _allowances[tokenId] + duration; 177 | require(claimIndex <= _epochDuration, "Duration exceeds available allowance"); 178 | amount = getAllowanceAtEpoch(mintEpoch, duration); 179 | _totals[mintEpoch].supplyClaimed += amount; 180 | _allowances[tokenId] += duration; 181 | 182 | if (to == address(0)) { 183 | oco.trackBurn(msg.sender, amount); 184 | } else { 185 | oco.mint(to, amount); 186 | } 187 | 188 | emit Claim(msg.sender, tokenId, to, amount, claimIndex); 189 | if (mintEpoch == currEpoch()) { 190 | _emitTotalBalancesUpdate(mintEpoch); 191 | } 192 | } 193 | 194 | /// @notice Invests ETH to buy OCO tokens for a specified epoch. 195 | /// @param epoch The epoch in which to buy tokens. 196 | /// @return remainder The remainder of ETH returned to the buyer if not fully utilized. 197 | /// @dev When buying in the current epoch, the settlement is triggered and the duration is adjusted. 198 | /// The ETH value is divided equally over the remaining blocks. 199 | function buy(uint32 epoch) public payable nonReentrant returns (uint128) { 200 | uint48 duration = _epochDuration; 201 | uint128 value = SafeCast.toUint128(msg.value); 202 | require(value > 0, "Value must be higher than zero"); 203 | require(epoch >= currEpoch(), "Cannot buy past epoch"); 204 | if (epoch == currEpoch()) { 205 | _settle(epoch); 206 | duration -= blockIndex(); 207 | } 208 | require(getAllowanceAtEpoch(epoch, duration) > 0, "Nothing to buy"); 209 | 210 | uint128 remainder = value % duration; 211 | uint128 valuePerBlock = value / duration; 212 | require(valuePerBlock > 0, "Invalid valuePerBlock"); 213 | 214 | _balances[balancesKey(epoch, msg.sender)].valuePerBlk += valuePerBlock; 215 | _totals[epoch].valueInvested += (value - remainder); 216 | 217 | if (remainder > 0) { 218 | (bool sent,) = payable(msg.sender).call{value: remainder}(""); 219 | require(sent, "Return of remainder failed"); 220 | } 221 | 222 | emit Buy(msg.sender, epoch, valuePerBlock, remainder); 223 | if (epoch == currEpoch()) { 224 | _emitTotalBalancesUpdate(epoch); 225 | } 226 | return remainder; 227 | } 228 | 229 | /// @notice Settles invested ETH into OCO tokens for the specified epoch. 230 | /// @param epoch The epoch to settle. 231 | /// @return amount The amount of OCO tokens minted as a result of settling. 232 | /// @dev Can only settle for the current or past epochs. 233 | function settle(uint32 epoch) public nonReentrant returns (uint128 amount) { 234 | require(epoch <= currEpoch(), "Cannot settle future epoch"); 235 | return _settle(epoch); 236 | } 237 | 238 | function _settle(uint32 epoch) internal returns (uint128 amount) { 239 | AccountInfo storage acc = _balances[balancesKey(epoch, msg.sender)]; 240 | uint48 settleIndex = epoch == currEpoch() ? blockIndex() : _epochDuration; 241 | if (acc.lastSettle < settleIndex) { 242 | uint48 duration = settleIndex - acc.lastSettle; 243 | uint128 value = acc.valuePerBlk * duration; 244 | uint256 amountQ128 = settlePrice(epoch, value); 245 | amount = uint128(amountQ128 / Q128); 246 | if (amount > 0) { 247 | oco.mint(msg.sender, amount); 248 | TotalBalances storage t = _totals[epoch]; 249 | t.valueSettled += value; 250 | t.supplySettled += amountQ128; 251 | emit Settle(msg.sender, value, amountQ128, duration); 252 | if (epoch == currEpoch()) { 253 | _emitTotalBalancesUpdate(epoch); 254 | } 255 | } 256 | acc.lastSettle = settleIndex; 257 | } 258 | } 259 | 260 | /// @notice Withdraws ETH proceeds from unclaimed allowance for a given Pileus token. 261 | /// @param tokenId The Pileus token id. 262 | /// @return value The amount of ETH withdrawn (in wei). 263 | /// @dev Caller must be the token owner or approved. Withdrawal can only occur for current or past epochs. 264 | function withdraw(uint256 tokenId) public nonReentrant returns (uint128 value) { 265 | (address owner, uint48 mintBlock) = pileus.propsOf(tokenId); 266 | require( 267 | msg.sender == owner || pileus.getApproved(tokenId) == msg.sender 268 | || pileus.isApprovedForAll(owner, msg.sender), 269 | "Caller is not token owner nor approved" 270 | ); 271 | uint32 mintEpoch = SafeCast.toUint32(mintBlock / _epochDuration); 272 | require(mintEpoch <= currEpoch(), "Cannot withdraw future epoch"); 273 | return _withdraw(tokenId, mintEpoch); 274 | } 275 | 276 | /// @notice Internal function that processes the withdrawal of ETH proceeds. 277 | /// @param tokenId The Pileus token id. 278 | /// @param mintEpoch The epoch in which the token was minted. 279 | /// @return value The computed ETH value withdrawn (in wei). 280 | /// @dev Updates the token's allowance index and emits a Withdraw event. 281 | function _withdraw(uint256 tokenId, uint32 mintEpoch) internal returns (uint128 value) { 282 | uint48 withdrawIndex = mintEpoch == currEpoch() ? blockIndex() : _epochDuration; 283 | uint48 lastWithdraw = _allowances[tokenId]; 284 | if (lastWithdraw < withdrawIndex) { 285 | uint128 amount = getAllowanceAtEpoch(mintEpoch, withdrawIndex - lastWithdraw); 286 | uint256 valueQ128 = withdrawPrice(mintEpoch, amount); 287 | value = uint128(valueQ128 / Q128); 288 | TotalBalances storage t = _totals[mintEpoch]; 289 | t.valueWithdrawn += valueQ128; 290 | t.supplyWithdrawn += amount; 291 | _allowances[tokenId] = withdrawIndex; 292 | if (value > 0) { 293 | (bool sent,) = payable(msg.sender).call{value: value}(""); 294 | require(sent, "Withdrawal transfer failed"); 295 | } 296 | emit Withdraw(msg.sender, amount, valueQ128); 297 | if (mintEpoch == currEpoch()) { 298 | _emitTotalBalancesUpdate(mintEpoch); 299 | } 300 | } 301 | } 302 | 303 | function _emitTotalBalancesUpdate(uint32 epoch) internal { 304 | TotalBalances memory t = _totals[epoch]; 305 | uint128 totalSupply = uint128(getTotalAllowanceSupply(epoch)); 306 | emit TotalBalancesUpdate( 307 | totalSupply, 308 | t.supplyClaimed, 309 | t.supplyWithdrawn, 310 | t.supplySettled, 311 | t.valueInvested, 312 | t.valueSettled, 313 | t.valueWithdrawn 314 | ); 315 | } 316 | 317 | // ============================================================= 318 | // VIEW FUNCTIONS 319 | // ============================================================= 320 | 321 | /// @notice Returns the current block index within the active epoch. 322 | /// @return The block index relative to the epoch duration. 323 | function blockIndex() public view returns (uint48) { 324 | return uint48(block.number) % _epochDuration; 325 | } 326 | 327 | /// @notice Returns the current epoch number. 328 | /// @return The current epoch computed from the block number. 329 | function currEpoch() public view returns (uint32) { 330 | return SafeCast.toUint32(block.number / _epochDuration); 331 | } 332 | 333 | /// @notice Generates a unique key for an account's balance information. 334 | /// @param epoch The epoch for which the key is generated. 335 | /// @param account The account address. 336 | /// @return A unique uint256 key composed of the epoch and account. 337 | function balancesKey(uint32 epoch, address account) public pure returns (uint256) { 338 | return (uint256(epoch) << 160) | uint256(uint160(account)); 339 | } 340 | 341 | /// @notice Retrieves the account's investment information for a given epoch. 342 | /// @param epoch The epoch number. 343 | /// @param account The address of the account. 344 | /// @return valuePerBlk The ETH value invested per block. 345 | /// @return lastSettle The last block index when settlement occurred. 346 | function getAccountInfo(uint32 epoch, address account) external view returns (uint128, uint48) { 347 | AccountInfo memory acc = _balances[balancesKey(epoch, account)]; 348 | return (acc.valuePerBlk, acc.lastSettle); 349 | } 350 | 351 | /// @notice Returns the current allowance (in blocks) already claimed or withdrawn for a token. 352 | /// @param tokenId The Pileus token id. 353 | /// @return The current allowance index. 354 | function getAllowance(uint256 tokenId) external view returns (uint48) { 355 | return _allowances[tokenId]; 356 | } 357 | 358 | /// @notice Calculates the OCO token allowance for a given epoch and duration. 359 | /// @param epoch The epoch for which the allowance is computed. 360 | /// @param duration The duration (in blocks) to calculate allowance for. 361 | /// @return amount The computed OCO token amount for the specified duration. 362 | /// @dev Uses the allowanceSlope and allowanceIntercept parameters. 363 | function getAllowanceAtEpoch(uint32 epoch, uint48 duration) public view returns (uint128 amount) { 364 | if (duration > 0 && duration <= _epochDuration) { 365 | int256 allowancePerEpoch = (_allowanceSlope * int256(uint256(epoch))) + _allowanceIntercept; 366 | if (allowancePerEpoch > 0) { 367 | amount = SafeCast.toUint128(Math.mulDiv(uint256(allowancePerEpoch), duration, _epochDuration * Q128)); 368 | } 369 | } 370 | } 371 | 372 | /// @notice Retrieves the current allowance calculation parameters. 373 | /// @return allowanceSlope The current allowance slope. 374 | /// @return allowanceIntercept The current allowance intercept. 375 | function getAllowanceParams() external view returns (int256, int256) { 376 | return (_allowanceSlope, _allowanceIntercept); 377 | } 378 | 379 | /// @notice Computes the total OCO allowance supply for an epoch. 380 | /// @param epoch The epoch number. 381 | /// @return totalSupply The total supply of OCO tokens available for allowance, 382 | /// calculated as the Pileus total supply multiplied by the allowance per epoch. 383 | /// @dev Uses current supply or past supply depending on the epoch. 384 | function getTotalAllowanceSupply(uint32 epoch) public view returns (uint256 totalSupply) { 385 | if (epoch == currEpoch()) { 386 | totalSupply = pileus.getTotalSupply(); 387 | } else { 388 | uint48 epochEnd = (epoch + 1) * _epochDuration; 389 | require(epochEnd > 0, "Epoch end must be greater than zero"); 390 | totalSupply = pileus.getPastTotalSupply(epochEnd - 1); 391 | } 392 | totalSupply *= getAllowanceAtEpoch(epoch, _epochDuration); 393 | } 394 | 395 | /// @notice Returns the aggregated totals for a given epoch. 396 | /// @param epoch The epoch number. 397 | /// @return supplyClaimed Total claimed OCO tokens. 398 | /// @return supplySettled Total settled OCO tokens (fixed-point Q128). 399 | /// @return supplyWithdrawn Total withdrawn OCO tokens. 400 | /// @return valueInvested Total ETH invested (in wei). 401 | /// @return valueSettled Total ETH settled (in wei). 402 | /// @return valueWithdrawn Total ETH withdrawn (fixed-point Q128). 403 | function getTotals(uint32 epoch) external view returns (uint128, uint256, uint128, uint128, uint128, uint256) { 404 | TotalBalances memory t = _totals[epoch]; 405 | return (t.supplyClaimed, t.supplySettled, t.supplyWithdrawn, t.valueInvested, t.valueSettled, t.valueWithdrawn); 406 | } 407 | 408 | /// @notice Calculates the settlement price for a given invested ETH value. 409 | /// @param epoch The epoch number. 410 | /// @param value The invested ETH value (in wei) to be settled. 411 | /// @return amount The amount of OCO tokens (in Q128 fixed-point) computed for settlement. 412 | /// @dev The calculation is based on the remaining available allowance and the difference 413 | /// between invested and settled values. 414 | function settlePrice(uint32 epoch, uint128 value) public view returns (uint256 amount) { 415 | if (value > 0) { 416 | TotalBalances memory t = _totals[epoch]; 417 | uint256 supplyInvestedQ128 = (getTotalAllowanceSupply(epoch) - t.supplyClaimed) * Q128; 418 | if (t.valueSettled < t.valueInvested && t.supplySettled < supplyInvestedQ128) { 419 | amount = Math.mulDiv((supplyInvestedQ128 - t.supplySettled), value, (t.valueInvested - t.valueSettled)); 420 | } 421 | } 422 | } 423 | 424 | /// @notice Calculates the withdrawal price for a given amount of allowance. 425 | /// @param epoch The epoch number. 426 | /// @param amount The amount of OCO tokens for which to compute the ETH value. 427 | /// @return value The ETH value (in Q128 fixed-point) corresponding to the withdrawal. 428 | /// @dev The computation considers the remaining invested ETH and allowance that has not yet been withdrawn. 429 | function withdrawPrice(uint32 epoch, uint128 amount) public view returns (uint256 value) { 430 | if (amount > 0) { 431 | TotalBalances memory t = _totals[epoch]; 432 | uint256 valueInvestedQ128 = t.valueInvested * Q128; 433 | uint256 supplyInvested = getTotalAllowanceSupply(epoch) - t.supplyClaimed; 434 | if (t.supplyWithdrawn < supplyInvested && t.valueWithdrawn < valueInvestedQ128) { 435 | value = 436 | Math.mulDiv((valueInvestedQ128 - t.valueWithdrawn), amount, (supplyInvested - t.supplyWithdrawn)); 437 | } 438 | } 439 | } 440 | } 441 | -------------------------------------------------------------------------------- /broadcast/Deploy.s.sol/480/run-1749684859.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xb8014616a7143f819664eb540e3b02b85a2b78b8f75a7c2b98858f16919af6a9", 5 | "transactionType": "CREATE2", 6 | "contractName": "TOTC", 7 | "contractAddress": "0x749d685098d25ba287dfdf43c390c0c4c939574a", 8 | "function": null, 9 | "arguments": [ 10 | "0x610Ac56bD97C7817e787A7D5cAf0346c4594037A", 11 | "0x600966eAfD19b5Fc051A1ea4175ea20fF305134B", 12 | "0xf919250541a98A36eADEf0e2f03FE0A9CA707fE3", 13 | "-70599777822791478862446529639759421080443289600000000000000000", 14 | "1663438023868150189486677747842492883722567680000000000000000000" 15 | ], 16 | "transaction": { 17 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 18 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 19 | "gas": "0x2f7435", 20 | "value": "0x0", 21 | "input": "0x3854717770fb8679b180c500656f7bc4f0ace22fa648de10b2d22a437aaea37760e060405234801561000f575f5ffd5b5060405161288b38038061288b83398101604081905261002e91610160565b846001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b610065816100fa565b50600180556001600160a01b0380851660a081905290841660c052604080516329c2e7c360e21b8152905163a70b9f0c916004808201926020929091908290030181865afa1580156100b9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100dd91906101ba565b65ffffffffffff16608052600291909155600355506101e6915050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116811461015d575f5ffd5b50565b5f5f5f5f5f60a08688031215610174575f5ffd5b855161017f81610149565b602087015190955061019081610149565b60408701519094506101a181610149565b6060870151608090970151959894975095949392505050565b5f602082840312156101ca575f5ffd5b815165ffffffffffff811681146101df575f5ffd5b9392505050565b60805160a05160c0516125e16102aa5f395f818161019801528181610efe01528181610f7e0152611dde01525f81816102e50152818161076701528181610806015281816108a501528181610afd01528181610b9c01528181610c3b015281816114fe015261162f01525f81816105200152818161067c015281816106f70152818161093c01528181610cc901528181610d9e0152818161107d0152818161145b01528181611586015281816116ce01528181611aa20152611d0f01526125e15ff3fe608060405260043610610126575f3560e01c80638da5cb5b116100a8578063c6a184921161006d578063c6a184921461038a578063c942b2e5146103a9578063c960174e14610482578063e2cec1a5146104b5578063ee3c43bb146104dc578063f2fde38b146104fb575f5ffd5b80638da5cb5b146102b85780639568baed146102d4578063b1fcd0ce14610307578063bed440d31461034c578063c538a4311461036b575f5ffd5b806361a6287f116100ee57806361a6287f14610228578063715018a61461024757806378639f981461025d5780637db5bd521461027c5780638879315d1461028f575f5ffd5b806317b3bc591461012a57806322501ad01461015a57806327eff9fd146101875780632c38ffcd146101d25780632e1a7d4d14610209575b5f5ffd5b348015610135575f5ffd5b5061013e61051a565b60405165ffffffffffff90911681526020015b60405180910390f35b348015610165575f5ffd5b50610179610174366004612106565b61054a565b604051908152602001610151565b348015610192575f5ffd5b506101ba7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610151565b3480156101dd575f5ffd5b506101f16101ec366004612159565b610667565b6040516001600160801b039091168152602001610151565b348015610214575f5ffd5b506101f1610223366004612183565b61073c565b348015610233575f5ffd5b506101f161024236600461219a565b6109f0565b348015610252575f5ffd5b5061025b610a70565b005b348015610268575f5ffd5b506101f16102773660046121c7565b610a83565b6101f161028a36600461219a565b611072565b34801561029a575f5ffd5b506102a361144b565b60405163ffffffff9091168152602001610151565b3480156102c3575f5ffd5b505f546001600160a01b03166101ba565b3480156102df575f5ffd5b506101ba7f000000000000000000000000000000000000000000000000000000000000000081565b348015610312575f5ffd5b50610326610321366004612206565b611486565b604080516001600160801b03909316835265ffffffffffff909116602083015201610151565b348015610357575f5ffd5b5061017961036636600461219a565b6114e1565b348015610376575f5ffd5b5061025b610385366004612230565b611705565b348015610395575f5ffd5b506101796103a4366004612206565b6117cb565b3480156103b4575f5ffd5b5061043f6103c336600461219a565b63ffffffff165f90815260066020908152604091829020825160c08101845281546001600160801b03808216808452600160801b92839004821695840186905260018501549684018790526002850154808316606086018190529390049091166080840181905260039094015460a09093018390529590929190565b604080516001600160801b0397881681526020810196909652938616938501939093529084166060840152909216608082015260a081019190915260c001610151565b34801561048d575f5ffd5b5061013e61049c366004612183565b5f9081526005602052604090205465ffffffffffff1690565b3480156104c0575f5ffd5b5060025460035460408051928352602083019190915201610151565b3480156104e7575f5ffd5b506101796104f6366004612106565b6117e7565b348015610506575f5ffd5b5061025b61051536600461225b565b611900565b5f6105457f00000000000000000000000000000000000000000000000000000000000000004361228a565b905090565b5f6001600160801b038216156106615763ffffffff83165f908152600660209081526040808320815160c08101835281546001600160801b03808216808452600160801b9283900482169684019690965260018401549483019490945260028301548085166060840152819004909316608082015260039091015460a082015292916105d5876114e1565b6105df91906122c9565b6105e991906122dc565b905081606001516001600160801b031682608001516001600160801b03161080156106175750808260400151105b1561065e5761065b82604001518261062f91906122c9565b856001600160801b03168460800151856060015161064d91906122f3565b6001600160801b031661193d565b92505b50505b92915050565b5f5f8265ffffffffffff161180156106af57507f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff168265ffffffffffff1611155b15610661575f6003548463ffffffff166002546106cc9190612312565b6106d69190612341565b90505f8113156107355761073261072d828565ffffffffffff16600160801b7f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1661072891906122dc565b61193d565b6119f3565b91505b5092915050565b5f610745611a2a565b604051638a1353fb60e01b8152600481018390525f9081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638a1353fb906024016040805180830381865afa1580156107ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107cf9190612360565b9092509050336001600160a01b038316148061087a575060405163020604bf60e21b81526004810185905233906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063081812fc90602401602060405180830381865afa15801561084b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086f919061238d565b6001600160a01b0316145b8061090e575060405163e985e9c560e01b81526001600160a01b0383811660048301523360248301527f0000000000000000000000000000000000000000000000000000000000000000169063e985e9c590604401602060405180830381865afa1580156108ea573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061090e91906123a8565b6109335760405162461bcd60e51b815260040161092a906123c7565b60405180910390fd5b5f61096e6109617f00000000000000000000000000000000000000000000000000000000000000008461240d565b65ffffffffffff16611a54565b905061097861144b565b63ffffffff168163ffffffff1611156109d35760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f74207769746864726177206675747572652065706f636800000000604482015260640161092a565b6109dd8582611a84565b93505050506109eb60018055565b919050565b5f6109f9611a2a565b610a0161144b565b63ffffffff168263ffffffff161115610a5c5760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420736574746c65206675747572652065706f6368000000000000604482015260640161092a565b610a6582611cd4565b90506109eb60018055565b610a78611f5c565b610a815f611f88565b565b5f610a8c611a2a565b5f8265ffffffffffff1611610adb5760405162461bcd60e51b8152602060048201526015602482015274273ab6361031b630b4b6b2b210323ab930ba34b7b760591b604482015260640161092a565b604051638a1353fb60e01b8152600481018590525f9081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638a1353fb906024016040805180830381865afa158015610b41573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b659190612360565b9092509050336001600160a01b0383161480610c10575060405163020604bf60e21b81526004810187905233906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063081812fc90602401602060405180830381865afa158015610be1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c05919061238d565b6001600160a01b0316145b80610ca4575060405163e985e9c560e01b81526001600160a01b0383811660048301523360248301527f0000000000000000000000000000000000000000000000000000000000000000169063e985e9c590604401602060405180830381865afa158015610c80573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca491906123a8565b610cc05760405162461bcd60e51b815260040161092a906123c7565b5f610cee6109617f00000000000000000000000000000000000000000000000000000000000000008461240d565b9050610cf861144b565b63ffffffff168163ffffffff161015610d535760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f7420636c61696d20706173742065706f6368000000000000000000604482015260640161092a565b610d5b61144b565b63ffffffff168163ffffffff1603610d7957610d778782611a84565b505b5f87815260056020526040812054610d9a90879065ffffffffffff16612438565b90507f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff168165ffffffffffff161115610e285760405162461bcd60e51b8152602060048201526024808201527f4475726174696f6e206578636565647320617661696c61626c6520616c6c6f77604482015263616e636560e01b606482015260840161092a565b610e328287610667565b63ffffffff83165f90815260066020526040812080549297508792909190610e649084906001600160801b0316612456565b82546001600160801b039182166101009390930a9283029190920219909116179055505f8881526005602052604081208054889290610eac90849065ffffffffffff16612438565b92506101000a81548165ffffffffffff021916908365ffffffffffff1602179055505f6001600160a01b0316876001600160a01b031603610f67576040516305ad189960e51b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5a3132090610f359033908990600401612475565b5f604051808303815f87803b158015610f4c575f5ffd5b505af1158015610f5e573d5f5f3e3d5ffd5b50505050610fe3565b6040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990610fb5908a908990600401612475565b5f604051808303815f87803b158015610fcc575f5ffd5b505af1158015610fde573d5f5f3e3d5ffd5b505050505b604080516001600160801b038716815265ffffffffffff831660208201526001600160a01b038916918a9133917fd74e97bdb11746c7acfbd74527f8915de088cd51c2ba295b5c716c06d028dc9f910160405180910390a461104361144b565b63ffffffff168263ffffffff160361105e5761105e82611fd7565b5050505061106b60018055565b9392505050565b5f61107b611a2a565b7f00000000000000000000000000000000000000000000000000000000000000005f6110a6346119f3565b90505f816001600160801b0316116111005760405162461bcd60e51b815260206004820152601e60248201527f56616c7565206d75737420626520686967686572207468616e207a65726f0000604482015260640161092a565b61110861144b565b63ffffffff168463ffffffff16101561115b5760405162461bcd60e51b8152602060048201526015602482015274086c2dcdcdee840c4eaf240e0c2e6e840cae0dec6d605b1b604482015260640161092a565b61116361144b565b63ffffffff168463ffffffff16036111945761117e84611cd4565b5061118761051a565b6111919083612497565b91505b5f61119f8584610667565b6001600160801b0316116111e65760405162461bcd60e51b815260206004820152600e60248201526d4e6f7468696e6720746f2062757960901b604482015260640161092a565b5f6111f965ffffffffffff8416836124b5565b90505f61120e65ffffffffffff8516846124e2565b90505f816001600160801b0316116112605760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642076616c7565506572426c6f636b60581b604482015260640161092a565b8060045f61126e89336117cb565b815260208101919091526040015f90812080549091906112989084906001600160801b0316612456565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555081836112c891906122f3565b63ffffffff87165f90815260066020526040812060020180549091906112f89084906001600160801b0316612456565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505f826001600160801b031611156113cd576040515f9033906001600160801b038516908381818185875af1925050503d805f8114611375576040519150601f19603f3d011682016040523d82523d5f602084013e61137a565b606091505b50509050806113cb5760405162461bcd60e51b815260206004820152601a60248201527f52657475726e206f662072656d61696e646572206661696c6564000000000000604482015260640161092a565b505b604080516001600160801b0380841682528416602082015263ffffffff88169133917f099c80a72263ee0fdf60a4370b3e72b1eb181d6a547d933f15981206d01078a3910160405180910390a361142261144b565b63ffffffff168663ffffffff160361143d5761143d86611fd7565b50925050506109eb60018055565b5f61054561148165ffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000164361250f565b611a54565b5f5f5f60045f61149687876117cb565b815260208082019290925260409081015f208151808301909252546001600160801b038116808352600160801b90910465ffffffffffff169190920181905290969095509350505050565b5f6114ea61144b565b63ffffffff168263ffffffff1603611583577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c4e41b226040518163ffffffff1660e01b8152600401602060405180830381865afa158015611558573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061157c9190612522565b90506116c8565b5f7f00000000000000000000000000000000000000000000000000000000000000006115b0846001612539565b63ffffffff166115c09190612555565b90505f8165ffffffffffff16116116255760405162461bcd60e51b815260206004820152602360248201527f45706f636820656e64206d7573742062652067726561746572207468616e207a60448201526265726f60e81b606482015260840161092a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016638e539e8c61165f600184612497565b6040516001600160e01b031960e084901b16815265ffffffffffff9091166004820152602401602060405180830381865afa1580156116a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116c49190612522565b9150505b6116f2827f0000000000000000000000000000000000000000000000000000000000000000610667565b610661906001600160801b0316826122dc565b61170d611f5c565b65ffffffffffff81161561178257438165ffffffffffff16146117825760405162461bcd60e51b815260206004820152602760248201527f43616e206f6e6c792062652065786563757465642061742073706563696669656044820152666420626c6f636b60c81b606482015260840161092a565b6002839055600382905560408051848152602081018490527f2259a4323a81d616baebfb2fe433c0e0b44a9ca13f4e28ffdb4a10d47b0375a891015b60405180910390a1505050565b6001600160a01b031660a09190911b63ffffffff60a01b161790565b5f6001600160801b038216156106615763ffffffff83165f908152600660209081526040808320815160c08101835281546001600160801b038082168352600160801b9182900481169583019590955260018301549382019390935260028201548085166060830181905290849004909416608082015260039091015460a0820152929161187591906122dc565b90505f825f01516001600160801b031661188e876114e1565b61189891906122c9565b90508083602001516001600160801b03161080156118b95750818360a00151105b156118f7576118f48360a00151836118d191906122c9565b866001600160801b031685602001516001600160801b03168461072891906122c9565b93505b50505092915050565b611908611f5c565b6001600160a01b03811661193157604051631e4fbdf760e01b81525f600482015260240161092a565b61193a81611f88565b50565b5f838302815f1985870982811083820303915050805f036119715783828161196757611967612276565b049250505061106b565b8084116119885761198860038515026011186120e2565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f6001600160801b03821115611a26576040516306dfcc6560e41b8152608060048201526024810183905260440161092a565b5090565b600260015403611a4d57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b5f63ffffffff821115611a26576040516306dfcc6560e41b8152602060048201526024810183905260440161092a565b5f5f611a8e61144b565b63ffffffff168363ffffffff1614611ac6577f0000000000000000000000000000000000000000000000000000000000000000611ace565b611ace61051a565b5f8581526005602052604090205490915065ffffffffffff90811690821681101561065e575f611b02856101ec8486612497565b90505f611b0f86836117e7565b9050611b1f600160801b8261250f565b63ffffffff87165f9081526006602052604081206003810180549398509092849290611b4c908490612576565b9091555050805483908290601090611b75908490600160801b90046001600160801b0316612456565b82546101009290920a6001600160801b038181021990931691831602179091555f8a8152600560205260409020805465ffffffffffff191665ffffffffffff89161790558716159050611c62576040515f9033906001600160801b038916908381818185875af1925050503d805f8114611c0a576040519150601f19603f3d011682016040523d82523d5f602084013e611c0f565b606091505b5050905080611c605760405162461bcd60e51b815260206004820152601a60248201527f5769746864726177616c207472616e73666572206661696c6564000000000000604482015260640161092a565b505b604080516001600160801b03851681526020810184905233917fe60d451977add447c195366df60ddde0e91a20b0ea9623cd8d8cc9a0d47d5b35910160405180910390a2611cae61144b565b63ffffffff168763ffffffff1603611cc957611cc987611fd7565b505050505092915050565b5f5f60045f611ce385336117cb565b81526020019081526020015f2090505f611cfb61144b565b63ffffffff168463ffffffff1614611d33577f0000000000000000000000000000000000000000000000000000000000000000611d3b565b611d3b61051a565b825490915065ffffffffffff808316600160801b909204161015611f555781545f90611d7690600160801b900465ffffffffffff1683612497565b83549091505f90611d999065ffffffffffff8416906001600160801b0316612589565b90505f611da6878361054a565b9050611db6600160801b8261250f565b95506001600160801b03861615611f31576040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990611e159033908a90600401612475565b5f604051808303815f87803b158015611e2c575f5ffd5b505af1158015611e3e573d5f5f3e3d5ffd5b5050505063ffffffff87165f908152600660205260409020600281018054849190601090611e7d908490600160801b90046001600160801b0316612456565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555081816001015f828254611eb49190612576565b9091555050604080516001600160801b03851681526020810184905265ffffffffffff861681830152905133917fa8a00bfd06926ec776566c67be2ea25273412ebcfbdbce5e161451ad56659b8f919081900360600190a2611f1461144b565b63ffffffff168863ffffffff1603611f2f57611f2f88611fd7565b505b5050825465ffffffffffff60801b1916600160801b65ffffffffffff841602178355505b5050919050565b5f546001600160a01b03163314610a815760405163118cdaa760e01b815233600482015260240161092a565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b63ffffffff81165f908152600660209081526040808320815160c08101835281546001600160801b038082168352600160801b918290048116958301959095526001830154938201939093526002820154808516606083015292909204909216608082015260039091015460a082015290612051836114e1565b90507f2d0a633db2b0915bcd688c247c68ef1d4241d595cb71aeda58a4d9b34a767afc81835f015184602001518560400151866060015187608001518860a001516040516117be97969594939291906001600160801b0397881681529587166020870152938616604086015260608501929092528416608084015290921660a082015260c081019190915260e00190565b634e487b715f52806020526024601cfd5b803563ffffffff811681146109eb575f5ffd5b5f5f60408385031215612117575f5ffd5b612120836120f3565b915060208301356001600160801b038116811461213b575f5ffd5b809150509250929050565b65ffffffffffff8116811461193a575f5ffd5b5f5f6040838503121561216a575f5ffd5b612173836120f3565b9150602083013561213b81612146565b5f60208284031215612193575f5ffd5b5035919050565b5f602082840312156121aa575f5ffd5b61106b826120f3565b6001600160a01b038116811461193a575f5ffd5b5f5f5f606084860312156121d9575f5ffd5b8335925060208401356121eb816121b3565b915060408401356121fb81612146565b809150509250925092565b5f5f60408385031215612217575f5ffd5b612220836120f3565b9150602083013561213b816121b3565b5f5f5f60608486031215612242575f5ffd5b833592506020840135915060408401356121fb81612146565b5f6020828403121561226b575f5ffd5b813561106b816121b3565b634e487b7160e01b5f52601260045260245ffd5b5f65ffffffffffff8316806122a1576122a1612276565b8065ffffffffffff84160691505092915050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610661576106616122b5565b8082028115828204841417610661576106616122b5565b6001600160801b038281168282160390811115610661576106616122b5565b8082025f8212600160ff1b8414161561232d5761232d6122b5565b8181058314821517610661576106616122b5565b8082018281125f83128015821682158216171561065e5761065e6122b5565b5f5f60408385031215612371575f5ffd5b825161237c816121b3565b602084015190925061213b81612146565b5f6020828403121561239d575f5ffd5b815161106b816121b3565b5f602082840312156123b8575f5ffd5b8151801515811461106b575f5ffd5b60208082526026908201527f43616c6c6572206973206e6f7420746f6b656e206f776e6572206e6f722061706040820152651c1c9bdd995960d21b606082015260800190565b5f65ffffffffffff83168061242457612424612276565b8065ffffffffffff84160491505092915050565b65ffffffffffff8181168382160190811115610661576106616122b5565b6001600160801b038181168382160190811115610661576106616122b5565b6001600160a01b039290921682526001600160801b0316602082015260400190565b65ffffffffffff8281168282160390811115610661576106616122b5565b5f6001600160801b038316806124cd576124cd612276565b806001600160801b0384160691505092915050565b5f6001600160801b038316806124fa576124fa612276565b806001600160801b0384160491505092915050565b5f8261251d5761251d612276565b500490565b5f60208284031215612532575f5ffd5b5051919050565b63ffffffff8181168382160190811115610661576106616122b5565b65ffffffffffff8181168382160290811690818114610735576107356122b5565b80820180821115610661576106616122b5565b6001600160801b038181168382160290811690818114610735576107356122b556fea2646970667358221220007ad6532e45df7f3fb9e72b51dfa7da754a5b20492c0fbcacf0133f6e10651e64736f6c634300081b0033000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a000000000000000000000000600966eafd19b5fc051a1ea4175ea20ff305134b000000000000000000000000f919250541a98a36eadef0e2f03fe0a9ca707fe3ffffffffffffd410ce76eee4afee0000000000000000000000000000000000000000000000040b28f74f044a9034000000000000000000000000000000000000", 22 | "nonce": "0x9", 23 | "chainId": "0x1e0" 24 | }, 25 | "additionalContracts": [], 26 | "isFixedGasLimit": false 27 | } 28 | ], 29 | "receipts": [ 30 | { 31 | "status": "0x1", 32 | "cumulativeGasUsed": "0x7a12c7", 33 | "logs": [ 34 | { 35 | "address": "0x749d685098d25ba287dfdf43c390c0c4c939574a", 36 | "topics": [ 37 | "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", 38 | "0x0000000000000000000000000000000000000000000000000000000000000000", 39 | "0x000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a" 40 | ], 41 | "data": "0x", 42 | "blockHash": "0x90fefe8ca200681332e585f2bf091b6a8628402252381c9f72e7f38bde381e97", 43 | "blockNumber": "0xe78bd0", 44 | "transactionHash": "0xb8014616a7143f819664eb540e3b02b85a2b78b8f75a7c2b98858f16919af6a9", 45 | "transactionIndex": "0xc", 46 | "logIndex": "0x7c", 47 | "removed": false 48 | } 49 | ], 50 | "logsBloom": "0x00000000000000000000000000000000000000000000000000800000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000010000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000100000000000000000000000000000000000000000000000", 51 | "type": "0x2", 52 | "transactionHash": "0xb8014616a7143f819664eb540e3b02b85a2b78b8f75a7c2b98858f16919af6a9", 53 | "transactionIndex": "0xc", 54 | "blockHash": "0x90fefe8ca200681332e585f2bf091b6a8628402252381c9f72e7f38bde381e97", 55 | "blockNumber": "0xe78bd0", 56 | "gasUsed": "0x225b16", 57 | "effectiveGasPrice": "0x39d49", 58 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 59 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 60 | "contractAddress": null, 61 | "l1BaseFeeScalar": "0x21f9", 62 | "l1BlobBaseFee": "0x1", 63 | "l1BlobBaseFeeScalar": "0xdd3ef", 64 | "l1Fee": "0x13af3b94100", 65 | "l1GasPrice": "0x6f5c5c54", 66 | "l1GasUsed": "0x14531" 67 | } 68 | ], 69 | "libraries": [], 70 | "pending": [], 71 | "returns": {}, 72 | "timestamp": 1749684859, 73 | "chain": 480, 74 | "commit": "1a37ffd" 75 | } -------------------------------------------------------------------------------- /broadcast/Deploy.s.sol/480/run-1744428937.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xa8f7b0f0b58e34847b00a268d177687109416250640f919ed510f4720d1c9d07", 5 | "transactionType": "CREATE2", 6 | "contractName": "Pileus", 7 | "contractAddress": "0x600966eafd19b5fc051a1ea4175ea20ff305134b", 8 | "function": null, 9 | "arguments": [ 10 | "0x610Ac56bD97C7817e787A7D5cAf0346c4594037A", 11 | "15778800", 12 | "2" 13 | ], 14 | "transaction": { 15 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 16 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 17 | "gas": "0x541957", 18 | "value": "0x0", 19 | "input": "0x3854717770fb8679b180c500656f7bc4f0ace22fa648de10b2d22a437aaea3776101a0604052348015610010575f5ffd5b5060405161470f38038061470f83398101604081905261002f9161032c565b816040518060400160405280600681526020016550696c65757360d01b815250604051806040016040528060018152602001603160f81b8152506040518060400160405280600681526020016550696c65757360d01b8152506040518060400160405280600381526020016214125360ea1b81525081600190816100b39190610411565b5060026100c08282610411565b506100d0915083905060076101fc565b610120526100df8160086101fc565b61014052815160208084019190912060e052815190820120610100524660a05261016b60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b60805250503060c052600165ffffffffffff8216116101d15760405162461bcd60e51b815260206004820152601660248201527f496e76616c69642065706f6368206475726174696f6e0000000000000000000060448201526064015b60405180910390fd5b65ffffffffffff16610160526101e75f8461022e565b5065ffffffffffff1661018052506105239050565b5f60208351101561021757610210836102d5565b9050610228565b816102228482610411565b5060ff90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166102ce575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556102863390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610228565b505f610228565b5f5f829050601f815111156102ff578260405163305a27a960e01b81526004016101c891906104cb565b805161030a82610500565b179392505050565b805165ffffffffffff81168114610327575f5ffd5b919050565b5f5f5f6060848603121561033e575f5ffd5b83516001600160a01b0381168114610354575f5ffd5b925061036260208501610312565b915061037060408501610312565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806103a157607f821691505b6020821081036103bf57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561040c57805f5260205f20601f840160051c810160208510156103ea5750805b601f840160051c820191505b81811015610409575f81556001016103f6565b50505b505050565b81516001600160401b0381111561042a5761042a610379565b61043e81610438845461038d565b846103c5565b6020601f821160018114610470575f83156104595750848201515b5f19600385901b1c1916600184901b178455610409565b5f84815260208120601f198516915b8281101561049f578785015182556020948501946001909201910161047f565b50848210156104bc57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b805160208083015191908110156103bf575f1960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051610160516101805161415d6105b25f395f818161040401528181610ce40152610d3201525f818161061b01528181610a7601528181610ab101528181610e280152610e7701525f6116cb01525f61169e01525f612c1f01525f612bf701525f612b5201525f612b7c01525f612ba6015261415d5ff3fe608060405234801561000f575f5ffd5b5060043610610297575f3560e01c80638879315d11610161578063aea0e78b116100ca578063d547741f11610084578063d547741f14610699578063dd947f14146106ac578063e74a84ea146106bf578063e7705db6146106d2578063e8a3d485146106e6578063e985e9c5146106ee575f5ffd5b8063aea0e78b1461063d578063b88d4fde14610645578063c1b3d95514610658578063c3cda5201461066b578063c4e41b221461067e578063c87b56dd14610686575f5ffd5b8063948113be1161011b578063948113be146105ce57806395d89b41146105e15780639ab24eb0146105e9578063a217fddf146105fc578063a22cb46514610603578063a70b9f0c14610616575f5ffd5b80638879315d146105255780638a1353fb146105425780638e539e8c1461058d5780638ea01f47146105a057806391d14854146105b357806391ddadf4146105c6575f5ffd5b80634378a6e3116102035780635be035a9116101bd5780635be035a9146104965780635c19a95c146104a95780636352211e146104bc57806370a08231146104cf5780637ecebe00146104e257806384b0196e1461050a575f5ffd5b80634378a6e3146103cd57806348b15166146103ff5780634bab1cf81461043d5780634bf5d7e914610450578063587cde1e146104585780635977043814610483575f5ffd5b806326d8e1e71161025457806326d8e1e71461035b5780632f2ff15d1461036e57806336568abe146103815780633a46b1a81461039457806342842e0e146103a757806342c67885146103ba575f5ffd5b806301ffc9a71461029b57806306fdde03146102c3578063081812fc146102d8578063095ea7b31461030357806323b872dd14610318578063248a9ca31461032b575b5f5ffd5b6102ae6102a93660046134ba565b610701565b60405190151581526020015b60405180910390f35b6102cb610711565b6040516102ba9190613503565b6102eb6102e6366004613515565b6107a1565b6040516001600160a01b0390911681526020016102ba565b610316610311366004613547565b6107c8565b005b61031661032636600461356f565b6107d7565b61034d610339366004613515565b5f9081526020819052604090206001015490565b6040519081526020016102ba565b6103166103693660046135a9565b610878565b61031661037c36600461361a565b61091d565b61031661038f36600461361a565b610941565b61034d6103a2366004613547565b610979565b6103166103b536600461356f565b610a0b565b6103166103c8366004613659565b610a25565b6103e06103db366004613515565b610a47565b6040805165ffffffffffff9384168152929091166020830152016102ba565b6104267f000000000000000000000000000000000000000000000000000000000000000081565b60405165ffffffffffff90911681526020016102ba565b6103e061044b366004613692565b610a71565b6102cb610ae2565b6102eb6104663660046136ab565b6001600160a01b039081165f908152600a60205260409020541690565b61034d6104913660046136ab565b610b5a565b61034d6104a43660046136c4565b610b67565b6103166104b73660046136ab565b610bc5565b6102eb6104ca366004613515565b610bd0565b61034d6104dd3660046136ab565b610bda565b61034d6104f03660046136ab565b6001600160a01b03165f9081526009602052604090205490565b610512610be7565b6040516102ba9796959493929190613701565b61052d610c29565b60405163ffffffff90911681526020016102ba565b610567610550366004613515565b5f908152600360205260409020549060d082901c90565b604080516001600160a01b03909316835265ffffffffffff9091166020830152016102ba565b61034d61059b366004613515565b610c3a565b61034d6105ae366004613515565b610cd1565b6102ae6105c136600461361a565b610d7a565b610426610da2565b61034d6105dc3660046136c4565b610dab565b6102cb610dcf565b61034d6105f73660046136ab565b610dde565b61034d5f81565b610316610611366004613797565b610e17565b6104267f000000000000000000000000000000000000000000000000000000000000000081565b61052d610e22565b6103166106533660046137d9565b610e59565b61052d610666366004613692565b610e71565b6103166106793660046138b6565b610e9c565b61034d610f58565b6102cb610694366004613515565b610f61565b6103166106a736600461361a565b6110a3565b6102cb6106ba366004613515565b6110c7565b6103166106cd366004613547565b6111a2565b61034d5f5160206141085f395f51905f5281565b6102cb6111c6565b6102ae6106fc366004613911565b611286565b5f61070b826112b3565b92915050565b60606001805461072090613939565b80601f016020809104026020016040519081016040528092919081815260200182805461074c90613939565b80156107975780601f1061076e57610100808354040283529160200191610797565b820191905f5260205f20905b81548152906001019060200180831161077a57829003601f168201915b5050505050905090565b5f6107ab826112f2565b505f828152600560205260409020546001600160a01b031661070b565b6107d382823361132a565b5050565b6001600160a01b03821661080557604051633250574960e11b81525f60048201526024015b60405180910390fd5b5f8181526003602052604081205460d01c9061082384843385611337565b9050846001600160a01b0316816001600160a01b031614610871576040516364283d7b60e01b81526001600160a01b03808716600483015260248201859052821660448201526064016107fc565b5050505050565b5f5160206141085f395f51905f5261088f81611365565b5f5b828110156109175761090f8484838181106108ae576108ae613971565b6108c492602060609092020190810191506136ab565b8585848181106108d6576108d6613971565b905060600201602001358686858181106108f2576108f2613971565b905060600201604001602081019061090a9190613692565b611372565b600101610891565b50505050565b5f8281526020819052604090206001015461093781611365565b61091783836113f1565b6001600160a01b038116331461096a5760405163334bd91960e11b815260040160405180910390fd5b6109748282611480565b505050565b5f5f610983610da2565b90508065ffffffffffff1683106109be57604051637669fc0f60e11b81526004810184905265ffffffffffff821660248201526044016107fc565b6109fa6109ca846114e9565b600b5f6109df886109da896114e9565b61151f565b81526020019081526020015f2061154590919063ffffffff16565b6001600160d01b0316949350505050565b61097483838360405180602001604052805f815250610e59565b5f5160206141085f395f51905f52610a3c81611365565b610917848484611372565b5f81815260036020526040812054819060d01c81610a6482610a71565b9296929550919350505050565b5f80807f0000000000000000000000000000000000000000000000000000000000000000610a9f81866139ad565b610aa991906139d8565b90505f610ad67f000000000000000000000000000000000000000000000000000000000000000083613a00565b91959194509092505050565b6060610aec6115f5565b65ffffffffffff16610afc610da2565b65ffffffffffff1614610b22576040516301bfc1c560e61b815260040160405180910390fd5b5060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b5f61070b826105dc610c29565b5f6001600160a01b038316610b91576040516322718ad960e21b81525f60048201526024016107fc565b60045f610b9e85856115ff565b81526020019081526020015f20545f14610bb9576001610bbb565b5f5b60ff169392505050565b336107d3818361161e565b5f61070b826112f2565b5f61070b826104a4610c29565b5f6060805f5f5f6060610bf8611697565b610c006116c4565b604080515f80825260208201909252600f60f81b9b939a50919850469750309650945092509050565b5f610c35610666610da2565b905090565b5f5f610c44610da2565b90508065ffffffffffff168310610c7f57604051637669fc0f60e11b81526004810184905265ffffffffffff821660248201526044016107fc565b610cc1610c8b846114e9565b600c5f610c9a610666886114e9565b63ffffffff1663ffffffff1681526020019081526020015f2061154590919063ffffffff16565b6001600160d01b03169392505050565b5f4342818410610d295765ffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016610d0e8386613a1e565b610d189190613a31565b610d229082613a48565b9250610d73565b65ffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016610d5c8584613a1e565b610d669190613a31565b610d709082613a1e565b92505b5050919050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f610c356115f5565b5f60045f610db985856115ff565b81526020019081526020015f2054905092915050565b60606002805461072090613939565b5f610e08600b5f610df685610df1610c29565b6115ff565b81526020019081526020015f206116f1565b6001600160d01b031692915050565b6107d3338383611729565b5f610c357f0000000000000000000000000000000000000000000000000000000000000000610e4f610da2565b6106669190613a00565b610e648484846107d7565b61091733858585856117c7565b5f61070b7f0000000000000000000000000000000000000000000000000000000000000000836139ad565b83421115610ec057604051632341d78760e11b8152600481018590526024016107fc565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b0388169181019190915260608101869052608081018590525f90610f3990610f319060a001604051602081830303815290604052805190602001206118ee565b85858561191a565b9050610f458187611946565b610f4f818861161e565b50505050505050565b5f610c35611998565b60605f5f610f6e84610a47565b65ffffffffffff16915065ffffffffffff1691505f610f8c83610cd1565b90505f610f9883610cd1565b90505f610fa4836119d3565b610fad866119d3565b610fb6846119d3565b610fbf876119d3565b604051602001610fd29493929190613a72565b60408051601f19818403018152828201909152600682526550696c65757360d01b602083015291505f90611005896119d3565b60405180604001604052806017815260200176536572766f732061642070696c65756d20766f6361726560481b81525061103e8b611a63565b6110478c6110c7565b8660405160200161105d96959493929190613c59565b6040516020818303038152906040529050611077816123d5565b6040516020016110879190613d6b565b6040516020818303038152906040529650505050505050919050565b5f828152602081905260409020600101546110bd81611365565b6109178383611480565b60605f5f6110d484610a47565b65ffffffffffff16915065ffffffffffff1691505f61112360408051808201909152601d81527f68747470733a2f2f6170702e70696c65756d2e6f72672f70696c657573000000602082015290565b90505f81611130876119d3565b611139866119d3565b611142866119d3565b61114b436119d3565b611154426119d3565b60405160200161116996959493929190613d9c565b60405160208183030381529060405290505f8251116111965760405180602001604052805f815250611198565b805b9695505050505050565b5f5160206141085f395f51905f526111b981611365565b610974838361090a610da2565b60605f6040518060400160405280600681526020016550696c65757360d01b81525060405180604001604052806017815260200176536572766f732061642070696c65756d20766f6361726560481b81525061122967b67a9854cdef3210611a63565b60408051808201909152601d81527f68747470733a2f2f6170702e70696c65756d2e6f72672f70696c65757300000060208201526040516020016112709493929190613e2c565b60408051601f1981840301815291905292915050565b6001600160a01b039182165f90815260066020908152604080832093909416825291909152205460ff1690565b5f6001600160e01b031982166380ac58cd60e01b14806112e357506001600160e01b03198216635b5e139f60e01b145b8061070b575061070b826123fb565b5f818152600360205260408120546001600160a01b03811661070b57604051637e27328960e01b8152600481018490526024016107fc565b610974838383600161242f565b5f5f61134586868686612533565b905061135c8187600161135787610e71565b612664565b95945050505050565b61136f8133612705565b50565b5f8281526003602052604090205460d081901c6001600160a01b038216156113be57846001600160a01b0316826001600160a01b0316146113b9576113b98286868461273e565b610871565b6113c9858585612759565b6001600160a01b038581165f908152600a60205260409020541661087157610871858661161e565b5f6113fc8383610d7a565b611479575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556114313390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161070b565b505f61070b565b5f61148b8383610d7a565b15611479575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161070b565b5f65ffffffffffff82111561151b576040516306dfcc6560e41b815260306004820152602481018390526044016107fc565b5090565b5f826001600160a01b031660a061153584610e71565b63ffffffff16901b179392505050565b81545f90818160058111156115a1575f61155e84612773565b6115689085613a1e565b5f8881526020902090915081015465ffffffffffff90811690871610156115915780915061159f565b61159c816001613a48565b92505b505b5f6115ae878785856128cb565b905080156115e8576115d2876115c5600184613a1e565b5f91825260209091200190565b54600160301b90046001600160d01b03166115ea565b5f5b979650505050505050565b5f610c35436114e9565b63ffffffff60a01b60a082901b166001600160a01b0383161792915050565b6001600160a01b038281165f818152600a602052604080822080548686166001600160a01b0319821681179092559151919094169392849290917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610974818361168a8661292a565b611692610c29565b612934565b6060610c357f00000000000000000000000000000000000000000000000000000000000000006007612a9d565b6060610c357f00000000000000000000000000000000000000000000000000000000000000006008612a9d565b80545f9080156117205761170a836115c5600184613a1e565b54600160301b90046001600160d01b0316611722565b5f5b9392505050565b6001600160a01b03821661175b57604051630b61174360e31b81526001600160a01b03831660048201526024016107fc565b6001600160a01b038381165f81815260066020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561087157604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611809908890889087908790600401613f05565b6020604051808303815f875af1925050508015611843575060408051601f3d908101601f1916820190925261184091810190613f37565b60015b6118aa573d808015611870576040519150601f19603f3d011682016040523d82523d5f602084013e611875565b606091505b5080515f036118a257604051633250574960e11b81526001600160a01b03851660048201526024016107fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146118e657604051633250574960e11b81526001600160a01b03851660048201526024016107fc565b505050505050565b5f61070b6118fa612b46565b8360405161190160f01b8152600281019290925260228201526042902090565b5f5f5f5f61192a88888888612c6f565b92509250925061193a8282612d37565b50909695505050505050565b6001600160a01b0382165f908152600960205260409020805460018101909155818114610974576040516301d4b62360e61b81526001600160a01b0384166004820152602481018290526044016107fc565b5f6119c5600c5f6119a7610c29565b63ffffffff1663ffffffff1681526020019081526020015f206116f1565b6001600160d01b0316905090565b60605f6119df83612def565b60010190505f8167ffffffffffffffff8111156119fe576119fe6137c5565b6040519080825280601f01601f191660200182016040528015611a28576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611a3257509392505050565b60605f604051806102000160405280662345414630423560c81b6001600160c81b0319166001600160c81b03191681526020016611a22222a1a12360c91b6001600160c81b0319168152602001662344304537434160c81b6001600160c81b031916815260200166046846a888888760cb1b6001600160c81b0319168152602001662341384438444360c81b6001600160c81b0319168152602001662338314334453760c81b6001600160c81b0319168152602001662337424243453760c81b6001600160c81b03191681526020016608cdd1508c914d60ca1b6001600160c81b03191681526020016608ce0e104d511160ca1b6001600160c81b031916815260200166119c999c9c221960c91b6001600160c81b03191681526020016608ce508e1050cd60ca1b6001600160c81b0319168152602001662339413730394560c81b6001600160c81b03191681526020016604672606c6670760cb1b6001600160c81b0319168152602001660233830353737360cc1b6001600160c81b0319168152602001662336383439353760c81b6001600160c81b0319168152602001662334363335334160c81b6001600160c81b03191681525090505f604051806102000160405280604051806040016040528060098152602001680181018989a971a1b960bd1b81525081526020016040518060400160405280600b81526020016a0189b171b1b901c1b171b160ad1b81525081526020016040518060400160405280600a81526020016901a9810189a1a17199a160b51b81525081526020016040518060400160405280600981526020016801a9810191c171c1b960bd1b81525081526020016040518060400160405280600881526020016701a98101c1b171b160c51b81525081526020016040518060400160405280600b81526020016a01c19971999901c1b171b160ad1b81525081526020016040518060400160405280600681526020016501898181018160d51b81525081526020016040518060400160405280600b81526020016a01898181018989a971a1b960ad1b81525081526020016040518060400160405280600a8152602001690189818101a9b971b99960b51b81525081526020016040518060400160405280600e81526020016d018989b171b1b90189a1a17199a160951b81525081526020016040518060400160405280600d81526020016c018989b171b1b90191c171c1b9609d1b81525081526020016040518060400160405280600b81526020016a0189a9810189a1a17199a160ad1b81525081526020016040518060400160405280600a8152602001690189a9810191c171c1b960b51b8152508152602001604051806040016040528060098152602001680189a98101c1b171b160bd1b81525081526020016040518060400160405280600e81526020016d0189c1997199990189a1a17199a160951b81525081526020016040518060400160405280600b81526020016a01918181018989a971a1b960ad1b81525081525090505f6040518061020001604052806040518060600160405280600f60ff168152602001600d60ff168152602001600e60ff1681525081526020016040518060600160405280600e60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518060600160405280600960ff168152602001600d60ff168152602001600b60ff1681525081526020016040518060600160405280600d60ff168152602001600760ff168152602001600960ff1681525081526020016040518060600160405280600160ff1681526020015f60ff168152602001600260ff1681525081526020016040518060600160405280600160ff168152602001600460ff168152602001600260ff1681525081526020016040518060600160405280600260ff168152602001600560ff168152602001600460ff1681525081526020016040518060600160405280600260ff168152602001600760ff168152602001600560ff1681525081526020016040518060600160405280600560ff168152602001600d60ff168152602001600760ff1681525081526020016040518060600160405280600560ff168152602001600860ff168152602001600d60ff1681525081526020016040518060600160405280600460ff168152602001600560ff168152602001600360ff1681525081526020016040518060600160405280600860ff168152602001600360ff168152602001600560ff1681525081526020016040518060600160405280600860ff168152602001600a60ff168152602001600360ff1681525081526020016040518060600160405280600d60ff168152602001600c60ff168152602001600a60ff1681525081526020016040518060600160405280600860ff168152602001600a60ff168152602001600d60ff1681525081526020016040518060600160405280600360ff168152602001600660ff168152602001600a60ff1681525081525090505f604051602001612222907f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222077696474683d2235313222206865696768743d223531322260208201527f207072657365727665417370656374526174696f3d22784d6964594d6964206d60408201527f656574222076696577426f783d2230203020323030203134342e3334223e00006060820152607e0190565b60408051601f1981840301815291905290505f5b60108160ff16101561237f57818561224f836004613f52565b60ff1689901c600f166010811061226857612268613971565b602002015185858460ff166010811061228357612283613971565b60200201515160ff166010811061229c5761229c613971565b602002015186868560ff16601081106122b7576122b7613971565b60200201516001602002015160ff16601081106122d6576122d6613971565b602002015187878660ff16601081106122f1576122f1613971565b60200201516040015160ff166010811061230d5761230d613971565b602002015188888760ff166010811061232857612328613971565b60200201515160ff166010811061234157612341613971565b602002015160405160200161235b96959493929190613f6e565b6040516020818303038152906040529150808061237790613ff2565b915050612236565b50806040516020016123919190614010565b60405160208183030381529060405290506123ab816123d5565b6040516020016123bb9190614031565b604051602081830303815290604052945050505050919050565b606061070b826040518060600160405280604081526020016140c8604091396001612ec6565b5f6001600160e01b03198216637965db0b60e01b148061070b57506301ffc9a760e01b6001600160e01b031983161461070b565b808061244357506001600160a01b03821615155b15612504575f612452846112f2565b90506001600160a01b0383161580159061247e5750826001600160a01b0316816001600160a01b031614155b8015612491575061248f8184611286565b155b156124ba5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016107fc565b81156125025783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260056020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b5f838152600360205260408120546001600160a01b0384161561255b5761255b818587613040565b6001600160a01b03811615612595576125765f865f5f61242f565b5f60045f612584848761151f565b815260208101919091526040015f20555b6001600160a01b038616156125fe575f6125af878561151f565b5f81815260046020526040902054909150156125e95760405163409db5b160e01b81526001600160a01b03881660048201526024016107fc565b5f908152600460205260409020859055612602565b5f92505b5f858152600360205260408082206001600160d01b031960d087901b166001600160a01b03808b1691821790925591518893918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a495945050505050565b6001600160a01b03841661269e5763ffffffff81165f908152600c6020526040902061269b906130a4612696856130af565b6130e2565b50505b6001600160a01b0383166126d35763ffffffff81165f908152600c602052604090206126d09061311a612696856130af565b50505b6001600160a01b038481165f908152600a60205260408082205486841683529120546109179291821691168484612934565b61270f8282610d7a565b6107d35760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016107fc565b61091784848460405180602001604052805f81525085613125565b610974838360405180602001604052805f8152508461313e565b5f60018211612780575090565b816001600160801b82106127995760809190911c9060401b5b6801000000000000000082106127b45760409190911c9060201b5b64010000000082106127cb5760209190911c9060101b5b6201000082106127e05760109190911c9060081b5b61010082106127f45760089190911c9060041b5b601082106128075760049190911c9060021b5b600482106128135760011b5b600302600190811c9081858161282b5761282b613985565b048201901c9050600181858161284357612843613985565b048201901c9050600181858161285b5761285b613985565b048201901c9050600181858161287357612873613985565b048201901c9050600181858161288b5761288b613985565b048201901c905060018185816128a3576128a3613985565b048201901c90506128c28185816128bc576128bc613985565b04821190565b90039392505050565b5f5b81831015612922575f6128e08484613156565b5f8781526020902090915065ffffffffffff86169082015465ffffffffffff16111561290e5780925061291c565b612919816001613a48565b93505b506128cd565b509392505050565b5f61070b82610bda565b826001600160a01b0316846001600160a01b03161415801561295557505f82115b15610917576001600160a01b038416156129f9575f5f612994600b5f61297b89876115ff565b81526020019081526020015f2061311a612696876130af565b6001600160d01b031691506001600160d01b03169150856001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516129ee929190918252602082015260400190565b60405180910390a250505b6001600160a01b03831615610917575f5f612a33600b5f612a1a88876115ff565b81526020019081526020015f206130a4612696876130af565b6001600160d01b031691506001600160d01b03169150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612a8d929190918252602082015260400190565b60405180910390a2505050505050565b606060ff8314612ab757612ab083613170565b905061070b565b818054612ac390613939565b80601f0160208091040260200160405190810160405280929190818152602001828054612aef90613939565b8015612b3a5780601f10612b1157610100808354040283529160200191612b3a565b820191905f5260205f20905b815481529060010190602001808311612b1d57829003601f168201915b5050505050905061070b565b5f306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015612b9e57507f000000000000000000000000000000000000000000000000000000000000000046145b15612bc857507f000000000000000000000000000000000000000000000000000000000000000090565b610c35604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612ca857505f91506003905082612d2d565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015612cf9573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116612d2457505f925060019150829050612d2d565b92505f91508190505b9450945094915050565b5f826003811115612d4a57612d4a614062565b03612d53575050565b6001826003811115612d6757612d67614062565b03612d855760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115612d9957612d99614062565b03612dba5760405163fce698f760e01b8152600481018290526024016107fc565b6003826003811115612dce57612dce614062565b036107d3576040516335e2f38360e21b8152600481018290526024016107fc565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310612e2d5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612e59576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310612e7757662386f26fc10000830492506010015b6305f5e1008310612e8f576305f5e100830492506008015b6127108310612ea357612710830492506004015b60648310612eb5576064830492506002015b600a831061070b5760010192915050565b606083515f03612ee4575060408051602081019091525f8152611722565b5f82612f1457600385516004612efa9190613a31565b612f05906002613a48565b612f0f9190614076565b612f39565b600385516002612f249190613a48565b612f2e9190614076565b612f39906004613a31565b90505f8167ffffffffffffffff811115612f5557612f556137c5565b6040519080825280601f01601f191660200182016040528015612f7f576020820181803683370190505b509050600185016020820187885189016020810180515f82525b82841015612ff4576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f8116870151865350600185019450612f99565b90525050851561193a57600388510660018114613018576002811461302b57613033565b603d6001830353603d6002830353613033565b603d60018303535b5050909695505050505050565b61304b8383836131ad565b610974576001600160a01b03831661307957604051637e27328960e01b8152600481018290526024016107fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016107fc565b5f6117228284614089565b5f6001600160d01b0382111561151b576040516306dfcc6560e41b815260d06004820152602481018390526044016107fc565b5f5f61310d6130ef610da2565b6131056130fb886116f1565b868863ffffffff16565b879190613211565b915091505b935093915050565b5f61172282846140a8565b6131318585858461321e565b61087133868686866117c7565b6131498484836132cc565b610917335f8686866117c7565b5f6131646002848418614076565b61172290848416613a48565b60605f61317c8361332e565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b5f6001600160a01b038316158015906132095750826001600160a01b0316846001600160a01b031614806131e657506131e68484611286565b8061320957505f828152600560205260409020546001600160a01b038481169116145b949350505050565b5f8061310d858585613355565b6001600160a01b03831661324757604051633250574960e11b81525f60048201526024016107fc565b5f61325484845f85611337565b90506001600160a01b03811661328057604051637e27328960e01b8152600481018490526024016107fc565b846001600160a01b0316816001600160a01b031614610871576040516364283d7b60e01b81526001600160a01b03808716600483015260248201859052821660448201526064016107fc565b6001600160a01b0383166132f557604051633250574960e11b81525f60048201526024016107fc565b5f61330284845f85611337565b90506001600160a01b03811615610917576040516339e3563760e11b81525f60048201526024016107fc565b5f60ff8216601f81111561070b57604051632cd44ac360e21b815260040160405180910390fd5b82545f908190801561344b575f613371876115c5600185613a1e565b805490915065ffffffffffff80821691600160301b90046001600160d01b03169088168211156133b457604051632520601d60e01b815260040160405180910390fd5b8765ffffffffffff168265ffffffffffff16036133ed57825465ffffffffffff16600160301b6001600160d01b0389160217835561343d565b6040805180820190915265ffffffffffff808a1682526001600160d01b03808a1660208085019182528d54600181018f555f8f81529190912094519151909216600160301b029216919091179101555b945085935061311292505050565b50506040805180820190915265ffffffffffff80851682526001600160d01b0380851660208085019182528854600181018a555f8a815291822095519251909316600160301b029190931617920191909155905081613112565b6001600160e01b03198116811461136f575f5ffd5b5f602082840312156134ca575f5ffd5b8135611722816134a5565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61172260208301846134d5565b5f60208284031215613525575f5ffd5b5035919050565b80356001600160a01b0381168114613542575f5ffd5b919050565b5f5f60408385031215613558575f5ffd5b6135618361352c565b946020939093013593505050565b5f5f5f60608486031215613581575f5ffd5b61358a8461352c565b92506135986020850161352c565b929592945050506040919091013590565b5f5f602083850312156135ba575f5ffd5b823567ffffffffffffffff8111156135d0575f5ffd5b8301601f810185136135e0575f5ffd5b803567ffffffffffffffff8111156135f6575f5ffd5b85602060608302840101111561360a575f5ffd5b6020919091019590945092505050565b5f5f6040838503121561362b575f5ffd5b8235915061363b6020840161352c565b90509250929050565b803565ffffffffffff81168114613542575f5ffd5b5f5f5f6060848603121561366b575f5ffd5b6136748461352c565b92506020840135915061368960408501613644565b90509250925092565b5f602082840312156136a2575f5ffd5b61172282613644565b5f602082840312156136bb575f5ffd5b6117228261352c565b5f5f604083850312156136d5575f5ffd5b6136de8361352c565b9150602083013563ffffffff811681146136f6575f5ffd5b809150509250929050565b60ff60f81b8816815260e060208201525f61371f60e08301896134d5565b828103604084015261373181896134d5565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015613786578351835260209384019390920191600101613768565b50909b9a5050505050505050505050565b5f5f604083850312156137a8575f5ffd5b6137b18361352c565b9150602083013580151581146136f6575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b5f5f5f5f608085870312156137ec575f5ffd5b6137f58561352c565b93506138036020860161352c565b925060408501359150606085013567ffffffffffffffff811115613825575f5ffd5b8501601f81018713613835575f5ffd5b803567ffffffffffffffff81111561384f5761384f6137c5565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561387e5761387e6137c5565b604052818152828201602001891015613895575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f5f5f5f5f60c087890312156138cb575f5ffd5b6138d48761352c565b95506020870135945060408701359350606087013560ff811681146138f7575f5ffd5b9598949750929560808101359460a0909101359350915050565b5f5f60408385031215613922575f5ffd5b61392b8361352c565b915061363b6020840161352c565b600181811c9082168061394d57607f821691505b60208210810361396b57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f65ffffffffffff8316806139c4576139c4613985565b8065ffffffffffff84160491505092915050565b65ffffffffffff81811683821602908116908181146139f9576139f9613999565b5092915050565b65ffffffffffff818116838216019081111561070b5761070b613999565b8181038181111561070b5761070b613999565b808202811582820484141761070b5761070b613999565b8082018082111561070b5761070b613999565b5f81518060208401855e5f93019283525090919050565b7f5b7b22646973706c61795f74797065223a202264617465222c0000000000000081527f2274726169745f74797065223a20226372656174696f6e222c200000000000006019820152680113b30b63ab2911d160bd1b60338201525f613adb603c830187613a5b565b627d2c7b60e81b81527808991a5cdc1b185e57dd1e5c19488e88089b9d5b58995c888b603a1b60038201527f2274726169745f74797065223a20226372656174696f6e5f626c6f636b222c20601c820152680113b30b63ab2911d160bd1b603c820152613b4b6045820187613a5b565b627d2c7b60e81b81527f22646973706c61795f74797065223a202264617465222c0000000000000000006003820152601a0190506115ea613c4b613c45613bc2613c11613bec613bdd613bd784897f2274726169745f74797065223a202265787069726174696f6e222c20000000008152601c0190565b680113b30b63ab2911d160bd1b815260090190565b8c613a5b565b627d2c7b60e81b815260030190565b7808991a5cdc1b185e57dd1e5c19488e88089b9d5b58995c888b603a1b815260190190565b7f2274726169745f74797065223a202265787069726174696f6e5f626c6f636b22815261016160f51b602082015260220190565b86613a5b565b617d5d60f01b815260020190565b607b60f81b815268113730b6b2911d101160b91b60018201525f613c80600a830189613a5b565b61202360f01b8152613c956002820189613a5b565b72111610113232b9b1b934b83a34b7b7111d101160691b81529050613cbd6013820188613a5b565b6c1116101134b6b0b3b2911d101160991b81529050613cdf600d820187613a5b565b7f222c20226261636b67726f756e645f636f6c6f72223a202234323432343200008152731116101132bc3a32b93730b62fbab936111d101160611b601e8201529050613d2e6032820186613a5b565b7001116101130ba3a3934b13aba32b9911d1607d1b81529050613d546011820185613a5b565b607d60f81b81526001019998505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525f611722601d830184613a5b565b5f613da78289613a5b565b633f69643d60e01b8152613dbe6004820189613a5b565b90506226633d60e81b8152613dd66003820188613a5b565b90506226653d60e81b8152613dee6003820187613a5b565b90506226623d60e81b8152613e066003820186613a5b565b9050632674733d60e01b8152613e1f6004820185613a5b565b9998505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c00000000008152607b60f81b601b82015268113730b6b2911d101160b91b601c8201525f613e796025830187613a5b565b72111610113232b9b1b934b83a34b7b7111d101160691b8152613e9f6013820187613a5b565b711116101134b6b0b3b2afb230ba30911d101160711b81529050613ec66012820186613a5b565b731116101132bc3a32b93730b62fbab936111d101160611b81529050613eef6014820185613a5b565b61227d60f01b8152600201979650505050505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f90611198908301846134d5565b5f60208284031215613f47575f5ffd5b8151611722816134a5565b60ff81811683821602908116908181146139f9576139f9613999565b5f613f798289613a5b565b6e1e3837b63cb3b7b7103334b6361e9160891b81526001600160c81b03198816600f8201526911103837b4b73a399e9160b11b6016820152613fd9613fd3613fcd613fc7602085018b613a5b565b89613a5b565b87613a5b565b85613a5b565b6211179f60e91b81526003019998505050505050505050565b5f60ff821660ff810361400757614007613999565b60010192915050565b5f61401b8284613a5b565b651e17b9bb339f60d11b81526006019392505050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081525f611722601a830184613a5b565b634e487b7160e01b5f52602160045260245ffd5b5f8261408457614084613985565b500490565b6001600160d01b03818116838216019081111561070b5761070b613999565b6001600160d01b03828116828216039081111561070b5761070b61399956fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f0ce23c3e399818cfee81a7ab0880f714e53d7672b08df0fa62f2843416e1ea09a2646970667358221220a4ee67c4cac543ed205381fa73575428b1711f98a772859bed055c2e7933bb5c64736f6c634300081b0033000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a0000000000000000000000000000000000000000000000000000000000f0c3f00000000000000000000000000000000000000000000000000000000000000002", 20 | "nonce": "0x1", 21 | "chainId": "0x1e0" 22 | }, 23 | "additionalContracts": [], 24 | "isFixedGasLimit": false 25 | }, 26 | { 27 | "hash": "0xead8093321b742e05a6aa2fe3a9fb1f9dffe4d663c8bd017865581c637314c0b", 28 | "transactionType": "CREATE2", 29 | "contractName": "OCO", 30 | "contractAddress": "0xf919250541a98a36eadef0e2f03fe0a9ca707fe3", 31 | "function": null, 32 | "arguments": [ 33 | "0x610Ac56bD97C7817e787A7D5cAf0346c4594037A" 34 | ], 35 | "transaction": { 36 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 37 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 38 | "gas": "0x1330a7", 39 | "value": "0x0", 40 | "input": "0x3854717770fb8679b180c500656f7bc4f0ace22fa648de10b2d22a437aaea377608060405234801561000f575f5ffd5b506040516110cc3803806110cc83398101604081905261002e91610147565b604051806040016040528060058152602001644f3d433d4f60d81b815250604051806040016040528060038152602001624f434f60e81b8152508160039081610077919061020c565b506004610084828261020c565b5061009391505f90508261009a565b50506102c6565b5f8281526005602090815260408083206001600160a01b038516845290915281205460ff1661013e575f8381526005602090815260408083206001600160a01b03861684529091529020805460ff191660011790556100f63390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610141565b505f5b92915050565b5f60208284031215610157575f5ffd5b81516001600160a01b038116811461016d575f5ffd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061019c57607f821691505b6020821081036101ba57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561020757805f5260205f20601f840160051c810160208510156101e55750805b601f840160051c820191505b81811015610204575f81556001016101f1565b50505b505050565b81516001600160401b0381111561022557610225610174565b610239816102338454610188565b846101c0565b6020601f82116001811461026b575f83156102545750848201515b5f19600385901b1c1916600184901b178455610204565b5f84815260208120601f198516915b8281101561029a578785015182556020948501946001909201910161027a565b50848210156102b757868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b610df9806102d35f395ff3fe608060405234801561000f575f5ffd5b5060043610610153575f3560e01c806342966c68116100bf578063a217fddf11610079578063a217fddf146102ef578063a9059cbb146102f6578063b5a3132014610309578063d53913931461031c578063d547741f14610343578063dd62ed3e14610356575f5ffd5b806342966c681461025e57806370a082311461027157806379cc67901461029957806391c1e2c1146102ac57806391d14854146102d457806395d89b41146102e7575f5ffd5b8063248a9ca311610110578063248a9ca3146101e15780632b8c49e3146102035780632f2ff15d14610216578063313ce5671461022957806336568abe1461023857806340c10f191461024b575f5ffd5b806301ffc9a71461015757806306fdde031461017f578063095ea7b31461019457806318160ddd146101a757806318bf5077146101b957806323b872dd146101ce575b5f5ffd5b61016a610165366004610c0a565b61038e565b60405190151581526020015b60405180910390f35b61018761039e565b6040516101769190610c38565b61016a6101a2366004610c88565b61042e565b6002545b604051908152602001610176565b6101cc6101c7366004610c88565b610445565b005b61016a6101dc366004610cb0565b61049d565b6101ab6101ef366004610cea565b5f9081526005602052604090206001015490565b6101cc610211366004610c88565b6104c0565b6101cc610224366004610d01565b610510565b60405160128152602001610176565b6101cc610246366004610d01565b61053a565b6101cc610259366004610c88565b610572565b6101cc61026c366004610cea565b6105a6565b6101ab61027f366004610d2b565b6001600160a01b03165f9081526020819052604090205490565b6101cc6102a7366004610c88565b6105bd565b6101ab6102ba366004610d2b565b6001600160a01b03165f9081526006602052604090205490565b61016a6102e2366004610d01565b6105e0565b61018761060a565b6101ab5f81565b61016a610304366004610c88565b610619565b6101cc610317366004610c88565b610626565b6101ab7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6101cc610351366004610d01565b61065a565b6101ab610364366004610d44565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b5f6103988261067e565b92915050565b6060600380546103ad90610d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546103d990610d6c565b80156104245780601f106103fb57610100808354040283529160200191610424565b820191905f5260205f20905b81548152906001019060200180831161040757829003601f168201915b5050505050905090565b5f3361043b8185856106a2565b5060019392505050565b61044e336106af565b61045882826106de565b60405181815233906001600160a01b038416907fde22baff038e3a3e08407cbdf617deed74e869a7ba517df611e33131c6e6ea04906020015b60405180910390a35050565b5f336104aa858285610717565b6104b585858561078c565b506001949350505050565b6104c9336106af565b6104d382826107e9565b60405181815233906001600160a01b038416907fb90795a66650155983e242cac3e1ac1a4dc26f8ed2987f3ce416a34e00111fd490602001610491565b5f8281526005602052604090206001015461052a8161081d565b6105348383610827565b50505050565b6001600160a01b03811633146105635760405163334bd91960e11b815260040160405180910390fd5b61056d82826108b8565b505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661059c8161081d565b61056d83836106de565b6105b033826107e9565b6105ba3382610923565b50565b6105c8823383610717565b6105d282826107e9565b6105dc8282610923565b5050565b5f9182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6060600480546103ad90610d6c565b5f3361043b81858561078c565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66106508161081d565b61056d8383610923565b5f828152600560205260409020600101546106748161081d565b61053483836108b8565b5f6001600160e01b03198216637965db0b60e01b14806103985750610398826109a5565b61056d83838360016109d9565b6001600160a01b0381166028602160991b01146105ba576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03821661070c5760405163ec442f0560e01b81525f60048201526024015b60405180910390fd5b6105dc5f8383610aab565b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f198114610534578181101561077e57604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610703565b61053484848484035f6109d9565b6001600160a01b0383166107b557604051634b637e8f60e11b81525f6004820152602401610703565b6001600160a01b0382166107de5760405163ec442f0560e01b81525f6004820152602401610703565b61056d838383610aab565b6001600160a01b03821661081257604051634b637e8f60e11b81525f6004820152602401610703565b6105dc825f83610aab565b6105ba8133610bd1565b5f61083283836105e0565b6108b1575f8381526005602090815260408083206001600160a01b03861684529091529020805460ff191660011790556108693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610398565b505f610398565b5f6108c383836105e0565b156108b1575f8381526005602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610398565b6001600160a01b0382165f908152600660205260408120805483929061094a908490610da4565b90915550506001600160a01b0382165f818152600660209081526040918290205482519081529081018490527f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a910160405180910390a25050565b5f6001600160e01b03198216630cccc66560e21b148061039857506301ffc9a760e01b6001600160e01b0319831614610398565b6001600160a01b038416610a025760405163e602df0560e01b81525f6004820152602401610703565b6001600160a01b038316610a2b57604051634a1406b160e11b81525f6004820152602401610703565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561053457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610a9d91815260200190565b60405180910390a350505050565b6001600160a01b038316610ad5578060025f828254610aca9190610da4565b90915550610b459050565b6001600160a01b0383165f9081526020819052604090205481811015610b275760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610703565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b038216610b6157600280548290039055610b7f565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610bc491815260200190565b60405180910390a3505050565b610bdb82826105e0565b6105dc5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610703565b5f60208284031215610c1a575f5ffd5b81356001600160e01b031981168114610c31575f5ffd5b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b0381168114610c83575f5ffd5b919050565b5f5f60408385031215610c99575f5ffd5b610ca283610c6d565b946020939093013593505050565b5f5f5f60608486031215610cc2575f5ffd5b610ccb84610c6d565b9250610cd960208501610c6d565b929592945050506040919091013590565b5f60208284031215610cfa575f5ffd5b5035919050565b5f5f60408385031215610d12575f5ffd5b82359150610d2260208401610c6d565b90509250929050565b5f60208284031215610d3b575f5ffd5b610c3182610c6d565b5f5f60408385031215610d55575f5ffd5b610d5e83610c6d565b9150610d2260208401610c6d565b600181811c90821680610d8057607f821691505b602082108103610d9e57634e487b7160e01b5f52602260045260245ffd5b50919050565b8082018082111561039857634e487b7160e01b5f52601160045260245ffdfea264697066735822122047850d05be612390047972b3a8d1da62007b9f006ed15990270932ecb58a856164736f6c634300081b0033000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a", 41 | "nonce": "0x2", 42 | "chainId": "0x1e0" 43 | }, 44 | "additionalContracts": [], 45 | "isFixedGasLimit": false 46 | }, 47 | { 48 | "hash": "0x0dd9b34425ab4c6e31dd5debe49a6f167137c90e45d11cd765d62f3b4a417215", 49 | "transactionType": "CREATE2", 50 | "contractName": "TOTC", 51 | "contractAddress": "0x1638438ce0960a1f6a139ef87b292c0b62dbb3c3", 52 | "function": null, 53 | "arguments": [ 54 | "0x610Ac56bD97C7817e787A7D5cAf0346c4594037A", 55 | "0x600966eAfD19b5Fc051A1ea4175ea20fF305134B", 56 | "0xf919250541a98A36eADEf0e2f03FE0A9CA707fE3", 57 | "-70599777822791478862446529639759421080443289600000000000000000", 58 | "1663438023868150189486677747842492883722567680000000000000000000" 59 | ], 60 | "transaction": { 61 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 62 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 63 | "gas": "0x302ed2", 64 | "value": "0x0", 65 | "input": "0x3854717770fb8679b180c500656f7bc4f0ace22fa648de10b2d22a437aaea37760e060405234801561000f575f5ffd5b5060405161274238038061274283398101604081905261002e9161015c565b846001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b610065816100f6565b506001600160a01b0380851660a081905290841660c052604080516329c2e7c360e21b8152905163a70b9f0c916004808201926020929091908290030181865afa1580156100b5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100d991906101b6565b65ffffffffffff16608052600191909155600255506101e2915050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381168114610159575f5ffd5b50565b5f5f5f5f5f60a08688031215610170575f5ffd5b855161017b81610145565b602087015190955061018c81610145565b604087015190945061019d81610145565b6060870151608090970151959894975095949392505050565b5f602082840312156101c6575f5ffd5b815165ffffffffffff811681146101db575f5ffd5b9392505050565b60805160a05160c05161249c6102a65f395f818161019801528181610b4f0152818161115301526111d301525f81816102e50152818161074101528181610802015281816108a101528181610d5201528181610df101528181610e90015281816116d1015261180201525f81816105200152818161067c015281816106f70152818161093801528181610a8001528181610f1e01528181610ff3015281816112c10152818161162e01528181611759015281816118a10152611c4c015261249c5ff3fe608060405260043610610126575f3560e01c80638da5cb5b116100a8578063c6a184921161006d578063c6a184921461038a578063c942b2e5146103a9578063c960174e14610482578063e2cec1a5146104b5578063ee3c43bb146104dc578063f2fde38b146104fb575f5ffd5b80638da5cb5b146102b85780639568baed146102d4578063b1fcd0ce14610307578063bed440d31461034c578063c538a4311461036b575f5ffd5b806361a6287f116100ee57806361a6287f14610228578063715018a61461024757806378639f981461025d5780637db5bd521461027c5780638879315d1461028f575f5ffd5b806317b3bc591461012a57806322501ad01461015a57806327eff9fd146101875780632c38ffcd146101d25780632e1a7d4d14610209575b5f5ffd5b348015610135575f5ffd5b5061013e61051a565b60405165ffffffffffff90911681526020015b60405180910390f35b348015610165575f5ffd5b50610179610174366004611fc1565b61054a565b604051908152602001610151565b348015610192575f5ffd5b506101ba7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610151565b3480156101dd575f5ffd5b506101f16101ec366004612014565b610667565b6040516001600160801b039091168152602001610151565b348015610214575f5ffd5b506101f161022336600461203e565b61073c565b348015610233575f5ffd5b506101f1610242366004612055565b6109e2565b348015610252575f5ffd5b5061025b610ccd565b005b348015610268575f5ffd5b506101f1610277366004612082565b610ce0565b6101f161028a366004612055565b6112be565b34801561029a575f5ffd5b506102a361161e565b60405163ffffffff9091168152602001610151565b3480156102c3575f5ffd5b505f546001600160a01b03166101ba565b3480156102df575f5ffd5b506101ba7f000000000000000000000000000000000000000000000000000000000000000081565b348015610312575f5ffd5b506103266103213660046120c1565b611659565b604080516001600160801b03909316835265ffffffffffff909116602083015201610151565b348015610357575f5ffd5b50610179610366366004612055565b6116b4565b348015610376575f5ffd5b5061025b6103853660046120eb565b6118d8565b348015610395575f5ffd5b506101796103a43660046120c1565b61199e565b3480156103b4575f5ffd5b5061043f6103c3366004612055565b63ffffffff165f90815260056020908152604091829020825160c08101845281546001600160801b03808216808452600160801b92839004821695840186905260018501549684018790526002850154808316606086018190529390049091166080840181905260039094015460a09093018390529590929190565b604080516001600160801b0397881681526020810196909652938616938501939093529084166060840152909216608082015260a081019190915260c001610151565b34801561048d575f5ffd5b5061013e61049c36600461203e565b5f9081526004602052604090205465ffffffffffff1690565b3480156104c0575f5ffd5b5060015460025460408051928352602083019190915201610151565b3480156104e7575f5ffd5b506101796104f6366004611fc1565b6119ba565b348015610506575f5ffd5b5061025b610515366004612116565b611ad3565b5f6105457f000000000000000000000000000000000000000000000000000000000000000043612145565b905090565b5f6001600160801b038216156106615763ffffffff83165f908152600560209081526040808320815160c08101835281546001600160801b03808216808452600160801b9283900482169684019690965260018401549483019490945260028301548085166060840152819004909316608082015260039091015460a082015292916105d5876116b4565b6105df9190612184565b6105e99190612197565b905081606001516001600160801b031682608001516001600160801b03161080156106175750808260400151105b1561065e5761065b82604001518261062f9190612184565b856001600160801b03168460800151856060015161064d91906121ae565b6001600160801b0316611b10565b92505b50505b92915050565b5f5f8265ffffffffffff161180156106af57507f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff168265ffffffffffff1611155b15610661575f6002548463ffffffff166001546106cc91906121cd565b6106d691906121fc565b90505f8113156107355761073261072d828565ffffffffffff16600160801b7f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff166107289190612197565b611b10565b611bc7565b91505b5092915050565b5f5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638a1353fb856040518263ffffffff1660e01b815260040161078d91815260200190565b6040805180830381865afa1580156107a7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107cb919061221b565b9092509050336001600160a01b0383161480610876575060405163020604bf60e21b81526004810185905233906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063081812fc90602401602060405180830381865afa158015610847573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086b9190612248565b6001600160a01b0316145b8061090a575060405163e985e9c560e01b81526001600160a01b0383811660048301523360248301527f0000000000000000000000000000000000000000000000000000000000000000169063e985e9c590604401602060405180830381865afa1580156108e6573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061090a9190612263565b61092f5760405162461bcd60e51b815260040161092690612282565b60405180910390fd5b5f61096a61095d7f0000000000000000000000000000000000000000000000000000000000000000846122c8565b65ffffffffffff16611bfe565b905061097461161e565b63ffffffff168163ffffffff1611156109cf5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f74207769746864726177206675747572652065706f6368000000006044820152606401610926565b6109d98582611c2e565b95945050505050565b5f6109eb61161e565b63ffffffff168263ffffffff161115610a465760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420736574746c65206675747572652065706f63680000000000006044820152606401610926565b5f60035f610a54853361199e565b81526020019081526020015f2090505f610a6c61161e565b63ffffffff168463ffffffff1614610aa4577f0000000000000000000000000000000000000000000000000000000000000000610aac565b610aac61051a565b825490915065ffffffffffff808316600160801b909204161015610cc65781545f90610ae790600160801b900465ffffffffffff16836122f3565b83549091505f90610b0a9065ffffffffffff8416906001600160801b0316612311565b90505f610b17878361054a565b9050610b27600160801b82612333565b95506001600160801b03861615610ca2576040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990610b869033908a90600401612346565b5f604051808303815f87803b158015610b9d575f5ffd5b505af1158015610baf573d5f5f3e3d5ffd5b5050505063ffffffff87165f908152600560205260409020600281018054849190601090610bee908490600160801b90046001600160801b0316612368565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555081816001015f828254610c259190612387565b9091555050604080516001600160801b03851681526020810184905265ffffffffffff861681830152905133917fa8a00bfd06926ec776566c67be2ea25273412ebcfbdbce5e161451ad56659b8f919081900360600190a2610c8561161e565b63ffffffff168863ffffffff1603610ca057610ca088611e12565b505b5050825465ffffffffffff60801b1916600160801b65ffffffffffff841602178355505b5050919050565b610cd5611f1d565b610cde5f611f49565b565b5f5f8265ffffffffffff1611610d305760405162461bcd60e51b8152602060048201526015602482015274273ab6361031b630b4b6b2b210323ab930ba34b7b760591b6044820152606401610926565b604051638a1353fb60e01b8152600481018590525f9081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638a1353fb906024016040805180830381865afa158015610d96573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dba919061221b565b9092509050336001600160a01b0383161480610e65575060405163020604bf60e21b81526004810187905233906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063081812fc90602401602060405180830381865afa158015610e36573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5a9190612248565b6001600160a01b0316145b80610ef9575060405163e985e9c560e01b81526001600160a01b0383811660048301523360248301527f0000000000000000000000000000000000000000000000000000000000000000169063e985e9c590604401602060405180830381865afa158015610ed5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef99190612263565b610f155760405162461bcd60e51b815260040161092690612282565b5f610f4361095d7f0000000000000000000000000000000000000000000000000000000000000000846122c8565b9050610f4d61161e565b63ffffffff168163ffffffff161015610fa85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f7420636c61696d20706173742065706f63680000000000000000006044820152606401610926565b610fb061161e565b63ffffffff168163ffffffff1603610fce57610fcc8782611c2e565b505b5f87815260046020526040812054610fef90879065ffffffffffff1661239a565b90507f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff168165ffffffffffff16111561107d5760405162461bcd60e51b8152602060048201526024808201527f4475726174696f6e206578636565647320617661696c61626c6520616c6c6f77604482015263616e636560e01b6064820152608401610926565b6110878287610667565b63ffffffff83165f908152600560205260408120805492975087929091906110b99084906001600160801b0316612368565b82546001600160801b039182166101009390930a9283029190920219909116179055505f888152600460205260408120805488929061110190849065ffffffffffff1661239a565b92506101000a81548165ffffffffffff021916908365ffffffffffff1602179055505f6001600160a01b0316876001600160a01b0316036111bc576040516305ad189960e51b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5a313209061118a9033908990600401612346565b5f604051808303815f87803b1580156111a1575f5ffd5b505af11580156111b3573d5f5f3e3d5ffd5b50505050611238565b6040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f199061120a908a908990600401612346565b5f604051808303815f87803b158015611221575f5ffd5b505af1158015611233573d5f5f3e3d5ffd5b505050505b604080516001600160801b038716815265ffffffffffff831660208201526001600160a01b038916918a9133917fd74e97bdb11746c7acfbd74527f8915de088cd51c2ba295b5c716c06d028dc9f910160405180910390a461129861161e565b63ffffffff168263ffffffff16036112b3576112b382611e12565b505050509392505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000816112ea34611bc7565b90505f816001600160801b0316116113445760405162461bcd60e51b815260206004820152601e60248201527f56616c7565206d75737420626520686967686572207468616e207a65726f00006044820152606401610926565b61134c61161e565b63ffffffff168463ffffffff16101561139f5760405162461bcd60e51b8152602060048201526015602482015274086c2dcdcdee840c4eaf240e0c2e6e840cae0dec6d605b1b6044820152606401610926565b6113a761161e565b63ffffffff168463ffffffff16036113d8576113c2846109e2565b506113cb61051a565b6113d590836122f3565b91505b5f6113e38584610667565b6001600160801b03161161142a5760405162461bcd60e51b815260206004820152600e60248201526d4e6f7468696e6720746f2062757960901b6044820152606401610926565b5f61143d65ffffffffffff8416836123b8565b90505f61145265ffffffffffff8516846123e5565b90505f816001600160801b0316116114a45760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642076616c7565506572426c6f636b60581b6044820152606401610926565b8060035f6114b2893361199e565b815260208101919091526040015f90812080549091906114dc9084906001600160801b0316612368565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550818361150c91906121ae565b63ffffffff87165f908152600560205260408120600201805490919061153c9084906001600160801b0316612368565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505f826001600160801b031611156115a55760405133906001600160801b03841680156108fc02915f818181858888f193505050501580156115a3573d5f5f3e3d5ffd5b505b604080516001600160801b0380841682528416602082015263ffffffff88169133917f099c80a72263ee0fdf60a4370b3e72b1eb181d6a547d933f15981206d01078a3910160405180910390a36115fa61161e565b63ffffffff168663ffffffff16036116155761161586611e12565b50949350505050565b5f61054561165465ffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001643612333565b611bfe565b5f5f5f60035f611669878761199e565b815260208082019290925260409081015f208151808301909252546001600160801b038116808352600160801b90910465ffffffffffff169190920181905290969095509350505050565b5f6116bd61161e565b63ffffffff168263ffffffff1603611756577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c4e41b226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174f9190612412565b905061189b565b5f7f0000000000000000000000000000000000000000000000000000000000000000611783846001612429565b63ffffffff166117939190612445565b90505f8165ffffffffffff16116117f85760405162461bcd60e51b815260206004820152602360248201527f45706f636820656e64206d7573742062652067726561746572207468616e207a60448201526265726f60e81b6064820152608401610926565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016638e539e8c6118326001846122f3565b6040516001600160e01b031960e084901b16815265ffffffffffff9091166004820152602401602060405180830381865afa158015611873573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118979190612412565b9150505b6118c5827f0000000000000000000000000000000000000000000000000000000000000000610667565b610661906001600160801b031682612197565b6118e0611f1d565b65ffffffffffff81161561195557438165ffffffffffff16146119555760405162461bcd60e51b815260206004820152602760248201527f43616e206f6e6c792062652065786563757465642061742073706563696669656044820152666420626c6f636b60c81b6064820152608401610926565b6001839055600282905560408051848152602081018490527f2259a4323a81d616baebfb2fe433c0e0b44a9ca13f4e28ffdb4a10d47b0375a891015b60405180910390a1505050565b6001600160a01b031660a09190911b63ffffffff60a01b161790565b5f6001600160801b038216156106615763ffffffff83165f908152600560209081526040808320815160c08101835281546001600160801b038082168352600160801b9182900481169583019590955260018301549382019390935260028201548085166060830181905290849004909416608082015260039091015460a08201529291611a489190612197565b90505f825f01516001600160801b0316611a61876116b4565b611a6b9190612184565b90508083602001516001600160801b0316108015611a8c5750818360a00151105b15611aca57611ac78360a0015183611aa49190612184565b866001600160801b031685602001516001600160801b0316846107289190612184565b93505b50505092915050565b611adb611f1d565b6001600160a01b038116611b0457604051631e4fbdf760e01b81525f6004820152602401610926565b611b0d81611f49565b50565b5f838302815f1985870982811083820303915050805f03611b4457838281611b3a57611b3a612131565b0492505050611bc0565b808411611b5b57611b5b6003851502601118611f98565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b5f6001600160801b03821115611bfa576040516306dfcc6560e41b81526080600482015260248101839052604401610926565b5090565b5f63ffffffff821115611bfa576040516306dfcc6560e41b81526020600482015260248101839052604401610926565b5f5f611c3861161e565b63ffffffff168363ffffffff1614611c70577f0000000000000000000000000000000000000000000000000000000000000000611c78565b611c7861051a565b5f8581526004602052604090205490915065ffffffffffff90811690821681101561065e575f611cac856101ec84866122f3565b90505f611cb986836119ba565b9050611cc9600160801b82612333565b63ffffffff87165f9081526005602052604081206003810180549398509092849290611cf6908490612387565b9091555050805483908290601090611d1f908490600160801b90046001600160801b0316612368565b82546101009290920a6001600160801b038181021990931691831602179091555f8a8152600460205260409020805465ffffffffffff191665ffffffffffff89161790558716159050611da05760405133906001600160801b03881680156108fc02915f818181858888f19350505050158015611d9e573d5f5f3e3d5ffd5b505b604080516001600160801b03851681526020810184905233917fe60d451977add447c195366df60ddde0e91a20b0ea9623cd8d8cc9a0d47d5b35910160405180910390a2611dec61161e565b63ffffffff168763ffffffff1603611e0757611e0787611e12565b505050505092915050565b63ffffffff81165f908152600560209081526040808320815160c08101835281546001600160801b038082168352600160801b918290048116958301959095526001830154938201939093526002820154808516606083015292909204909216608082015260039091015460a082015290611e8c836116b4565b90507f2d0a633db2b0915bcd688c247c68ef1d4241d595cb71aeda58a4d9b34a767afc81835f015184602001518560400151866060015187608001518860a0015160405161199197969594939291906001600160801b0397881681529587166020870152938616604086015260608501929092528416608084015290921660a082015260c081019190915260e00190565b5f546001600160a01b03163314610cde5760405163118cdaa760e01b8152336004820152602401610926565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b715f52806020526024601cfd5b803563ffffffff81168114611fbc575f5ffd5b919050565b5f5f60408385031215611fd2575f5ffd5b611fdb83611fa9565b915060208301356001600160801b0381168114611ff6575f5ffd5b809150509250929050565b65ffffffffffff81168114611b0d575f5ffd5b5f5f60408385031215612025575f5ffd5b61202e83611fa9565b91506020830135611ff681612001565b5f6020828403121561204e575f5ffd5b5035919050565b5f60208284031215612065575f5ffd5b611bc082611fa9565b6001600160a01b0381168114611b0d575f5ffd5b5f5f5f60608486031215612094575f5ffd5b8335925060208401356120a68161206e565b915060408401356120b681612001565b809150509250925092565b5f5f604083850312156120d2575f5ffd5b6120db83611fa9565b91506020830135611ff68161206e565b5f5f5f606084860312156120fd575f5ffd5b833592506020840135915060408401356120b681612001565b5f60208284031215612126575f5ffd5b8135611bc08161206e565b634e487b7160e01b5f52601260045260245ffd5b5f65ffffffffffff83168061215c5761215c612131565b8065ffffffffffff84160691505092915050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561066157610661612170565b808202811582820484141761066157610661612170565b6001600160801b03828116828216039081111561066157610661612170565b8082025f8212600160ff1b841416156121e8576121e8612170565b818105831482151761066157610661612170565b8082018281125f83128015821682158216171561065e5761065e612170565b5f5f6040838503121561222c575f5ffd5b82516122378161206e565b6020840151909250611ff681612001565b5f60208284031215612258575f5ffd5b8151611bc08161206e565b5f60208284031215612273575f5ffd5b81518015158114611bc0575f5ffd5b60208082526026908201527f43616c6c6572206973206e6f7420746f6b656e206f776e6572206e6f722061706040820152651c1c9bdd995960d21b606082015260800190565b5f65ffffffffffff8316806122df576122df612131565b8065ffffffffffff84160491505092915050565b65ffffffffffff828116828216039081111561066157610661612170565b6001600160801b03818116838216029081169081811461073557610735612170565b5f8261234157612341612131565b500490565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160801b03818116838216019081111561066157610661612170565b8082018082111561066157610661612170565b65ffffffffffff818116838216019081111561066157610661612170565b5f6001600160801b038316806123d0576123d0612131565b806001600160801b0384160691505092915050565b5f6001600160801b038316806123fd576123fd612131565b806001600160801b0384160491505092915050565b5f60208284031215612422575f5ffd5b5051919050565b63ffffffff818116838216019081111561066157610661612170565b65ffffffffffff81811683821602908116908181146107355761073561217056fea2646970667358221220ba4008cc4717b34b586f015b9f2f6e4c731bee17cc13dd1d6f28535540ed5b8564736f6c634300081b0033000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a000000000000000000000000600966eafd19b5fc051a1ea4175ea20ff305134b000000000000000000000000f919250541a98a36eadef0e2f03fe0a9ca707fe3ffffffffffffd410ce76eee4afee0000000000000000000000000000000000000000000000040b28f74f044a9034000000000000000000000000000000000000", 66 | "nonce": "0x3", 67 | "chainId": "0x1e0" 68 | }, 69 | "additionalContracts": [], 70 | "isFixedGasLimit": false 71 | }, 72 | { 73 | "hash": "0xe5857b14806e665d27e75854d3d7f1208906e4a7e4836e00f7df2f4c60051571", 74 | "transactionType": "CALL", 75 | "contractName": "OCO", 76 | "contractAddress": "0xf919250541a98a36eadef0e2f03fe0a9ca707fe3", 77 | "function": "grantRole(bytes32,address)", 78 | "arguments": [ 79 | "0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6", 80 | "0x1638438CE0960a1f6A139eF87B292c0B62Dbb3c3" 81 | ], 82 | "transaction": { 83 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 84 | "to": "0xf919250541a98a36eadef0e2f03fe0a9ca707fe3", 85 | "gas": "0x115ee", 86 | "value": "0x0", 87 | "input": "0x2f2ff15d9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a60000000000000000000000001638438ce0960a1f6a139ef87b292c0b62dbb3c3", 88 | "nonce": "0x4", 89 | "chainId": "0x1e0" 90 | }, 91 | "additionalContracts": [], 92 | "isFixedGasLimit": false 93 | }, 94 | { 95 | "hash": "0x3f8ada3cb78c07698ca5eed3a0a6de63cea9bc5043bb96420fead9363cd6e3d7", 96 | "transactionType": "CREATE2", 97 | "contractName": "WorldIDVerifier", 98 | "contractAddress": "0xf556e738324de1c3169972b44ab4810a59ff58c0", 99 | "function": null, 100 | "arguments": [ 101 | "0x17B354dD2595411ff79041f930e491A4Df39A278", 102 | "app_90f83f92ae19202a0b776b9ad68e0864", 103 | "0x600966eAfD19b5Fc051A1ea4175ea20fF305134B" 104 | ], 105 | "transaction": { 106 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 107 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 108 | "gas": "0xb1110", 109 | "value": "0x0", 110 | "input": "0x3854717770fb8679b180c500656f7bc4f0ace22fa648de10b2d22a437aaea377610100604052600160c052348015610015575f5ffd5b50604051610a99380380610a99833981016040819052610034916100f1565b6001600160a01b03831660805260405161006b906100569084906020016101db565b60408051601f19818403018152919052610082565b60a0526001600160a01b031660e052506101ed9050565b5f60088260405160200161009691906101db565b60408051601f198184030181529190528051602090910120901c92915050565b6001600160a01b03811681146100ca575f5ffd5b50565b634e487b7160e01b5f52604160045260245ffd5b80516100ec816100b6565b919050565b5f5f5f60608486031215610103575f5ffd5b835161010e816100b6565b60208501519093506001600160401b03811115610129575f5ffd5b8401601f81018613610139575f5ffd5b80516001600160401b03811115610152576101526100cd565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610180576101806100cd565b604052818152828201602001881015610197575f5ffd5b8160208401602083015e5f602083830101528094505050506101bb604085016100e1565b90509250925092565b5f81518060208401855e5f93019283525090919050565b5f6101e682846101c4565b9392505050565b60805160a05160c05160e0516108586102415f395f8181605201528181609a0152818161011c015281816101b301528181610235015261045301525f61038601525f61030d01525f61035601526108585ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806342e1e9be14610038578063fc0c546a1461004d575b5f5ffd5b61004b610046366004610699565b610090565b005b6100747f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b5f5f86156101b1577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aea0e78b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100f4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101189190610705565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a70b9f0c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610176573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061019a919061072f565b6101aa9063ffffffff8416610754565b90506102b6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638879315d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102319190610705565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391ddadf46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561028f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b3919061072f565b90505b5f60405180604001604052806006815260200165636c61696d2d60d01b8152506102e58463ffffffff166104fd565b6040516020016102f692919061079f565b60405160208183030381529060405290505f6103527f00000000000000000000000000000000000000000000000000000000000000008360405160200161033e9291906107bb565b60405160208183030381529060405261058d565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bc778e3887f00000000000000000000000000000000000000000000000000000000000000006103d18c60405160200161033e919060609190911b6bffffffffffffffffffffffff1916815260140190565b8a868b6040518763ffffffff1660e01b81526004016103f5969594939291906107cc565b5f6040518083038186803b15801561040b575f5ffd5b505afa15801561041d573d5f5f3e3d5ffd5b50506040516342c6788560e01b81526001600160a01b038b81166004830152602482018a905265ffffffffffff871660448301527f00000000000000000000000000000000000000000000000000000000000000001692506342c6788591506064015f604051808303815f87803b158015610496575f5ffd5b505af11580156104a8573d5f5f3e3d5ffd5b505060405163ffffffff871681528892506001600160a01b038b1691507f520ce93ae595908e486e4ad7cc76e0f537d3deca5257e0db8e449940dcbc09ae9060200160405180910390a3505050505050505050565b60605f610509836105c1565b60010190505f8167ffffffffffffffff81111561052857610528610803565b6040519080825280601f01601f191660200182016040528015610552576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461055c57509392505050565b5f6008826040516020016105a19190610817565b60408051601f198184030181529190528051602090910120901c92915050565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106105ff5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061062b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061064957662386f26fc10000830492506010015b6305f5e1008310610661576305f5e100830492506008015b612710831061067557612710830492506004015b60648310610687576064830492506002015b600a8310610693576001015b92915050565b5f5f5f5f5f61018086880312156106ae575f5ffd5b853580151581146106bd575f5ffd5b945060208601356001600160a01b03811681146106d8575f5ffd5b9350604086013592506060860135915061018086018710156106f8575f5ffd5b5092959194509260800190565b5f60208284031215610715575f5ffd5b815163ffffffff81168114610728575f5ffd5b9392505050565b5f6020828403121561073f575f5ffd5b815165ffffffffffff81168114610728575f5ffd5b65ffffffffffff818116838216029081169081811461078157634e487b7160e01b5f52601160045260245ffd5b5092915050565b5f81518060208401855e5f93019283525090919050565b5f6107b36107ad8386610788565b84610788565b949350505050565b8281525f6107b36020830184610788565b5f6101a0820190508782528660208301528560408301528460608301528360808301526101008360a0840137979650505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f610728828461078856fea2646970667358221220d1abe60ceb4f030fe499b84797e5006fccb5b7580895597ba8e40ba116fdfbd664736f6c634300081b003300000000000000000000000017b354dd2595411ff79041f930e491a4df39a2780000000000000000000000000000000000000000000000000000000000000060000000000000000000000000600966eafd19b5fc051a1ea4175ea20ff305134b00000000000000000000000000000000000000000000000000000000000000246170705f393066383366393261653139323032613062373736623961643638653038363400000000000000000000000000000000000000000000000000000000", 111 | "nonce": "0x5", 112 | "chainId": "0x1e0" 113 | }, 114 | "additionalContracts": [], 115 | "isFixedGasLimit": false 116 | }, 117 | { 118 | "hash": "0x1c1e874f49d0da79f392f74987fe0f9f2143737a85d4d836cf2f2f03acd27bed", 119 | "transactionType": "CALL", 120 | "contractName": "Pileus", 121 | "contractAddress": "0x600966eafd19b5fc051a1ea4175ea20ff305134b", 122 | "function": "grantRole(bytes32,address)", 123 | "arguments": [ 124 | "0x0ce23c3e399818cfee81a7ab0880f714e53d7672b08df0fa62f2843416e1ea09", 125 | "0xf556e738324dE1C3169972b44Ab4810A59Ff58C0" 126 | ], 127 | "transaction": { 128 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 129 | "to": "0x600966eafd19b5fc051a1ea4175ea20ff305134b", 130 | "gas": "0x12640", 131 | "value": "0x0", 132 | "input": "0x2f2ff15d0ce23c3e399818cfee81a7ab0880f714e53d7672b08df0fa62f2843416e1ea09000000000000000000000000f556e738324de1c3169972b44ab4810a59ff58c0", 133 | "nonce": "0x6", 134 | "chainId": "0x1e0" 135 | }, 136 | "additionalContracts": [], 137 | "isFixedGasLimit": false 138 | } 139 | ], 140 | "receipts": [ 141 | { 142 | "status": "0x1", 143 | "cumulativeGasUsed": "0x16791b8", 144 | "logs": [ 145 | { 146 | "address": "0x600966eafd19b5fc051a1ea4175ea20ff305134b", 147 | "topics": [ 148 | "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", 149 | "0x0000000000000000000000000000000000000000000000000000000000000000", 150 | "0x000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a", 151 | "0x0000000000000000000000004e59b44847b379578588920ca78fbf26c0b4956c" 152 | ], 153 | "data": "0x", 154 | "blockHash": "0x5501d6699029c8eaa3ce307424beffb963983cd4d02e37346021b3ecdecd54a9", 155 | "blockNumber": "0xbf724a", 156 | "transactionHash": "0xa8f7b0f0b58e34847b00a268d177687109416250640f919ed510f4720d1c9d07", 157 | "transactionIndex": "0x33", 158 | "logIndex": "0x237", 159 | "removed": false 160 | } 161 | ], 162 | "logsBloom": "0x00000004000000000000000000000000000000000000000000008000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000400000000000000000000000000000000000000000000000000000010000001000000000000080000000000000000001000000000000000000000000400000000000001000000000000000000000000000000000000000000000000000000000000100000000000020000000000000000000000000000000000080000000000000000000000000000000", 163 | "type": "0x2", 164 | "transactionHash": "0xa8f7b0f0b58e34847b00a268d177687109416250640f919ed510f4720d1c9d07", 165 | "transactionIndex": "0x33", 166 | "blockHash": "0x5501d6699029c8eaa3ce307424beffb963983cd4d02e37346021b3ecdecd54a9", 167 | "blockNumber": "0xbf724a", 168 | "gasUsed": "0x3980eb", 169 | "effectiveGasPrice": "0x18aa6", 170 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 171 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 172 | "contractAddress": null, 173 | "l1BaseFeeScalar": "0x21f9", 174 | "l1BlobBaseFee": "0x167ba504", 175 | "l1BlobBaseFeeScalar": "0xdd3ef", 176 | "l1Fee": "0x3a085c2f54f", 177 | "l1GasPrice": "0x1a6766f6", 178 | "l1GasUsed": "0x269c2" 179 | }, 180 | { 181 | "status": "0x1", 182 | "cumulativeGasUsed": "0x12e4c6", 183 | "logs": [ 184 | { 185 | "address": "0xf919250541a98a36eadef0e2f03fe0a9ca707fe3", 186 | "topics": [ 187 | "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", 188 | "0x0000000000000000000000000000000000000000000000000000000000000000", 189 | "0x000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a", 190 | "0x0000000000000000000000004e59b44847b379578588920ca78fbf26c0b4956c" 191 | ], 192 | "data": "0x", 193 | "blockHash": "0x758fe671c3ed5f7f3f5a0335c83a401de9a64a5db7a0aec1f1d7c623e1f61c0a", 194 | "blockNumber": "0xbf724f", 195 | "transactionHash": "0xead8093321b742e05a6aa2fe3a9fb1f9dffe4d663c8bd017865581c637314c0b", 196 | "transactionIndex": "0x4", 197 | "logIndex": "0x9", 198 | "removed": false 199 | } 200 | ], 201 | "logsBloom": "0x00000004000000000000000000000000000000000000000020000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000008000000000000000000000000000000000000000000000000000010000001000000000000000000000000000000001000000000000000000000000400000000000001000000000008000000000000000000000000000000000000000000000000100000000000020000000000000000000000000000000000080000000000000000000000000000000", 202 | "type": "0x2", 203 | "transactionHash": "0xead8093321b742e05a6aa2fe3a9fb1f9dffe4d663c8bd017865581c637314c0b", 204 | "transactionIndex": "0x4", 205 | "blockHash": "0x758fe671c3ed5f7f3f5a0335c83a401de9a64a5db7a0aec1f1d7c623e1f61c0a", 206 | "blockNumber": "0xbf724f", 207 | "gasUsed": "0xde4ad", 208 | "effectiveGasPrice": "0x18aa7", 209 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 210 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 211 | "contractAddress": null, 212 | "l1BaseFeeScalar": "0x21f9", 213 | "l1BlobBaseFee": "0x167ba504", 214 | "l1BlobBaseFeeScalar": "0xdd3ef", 215 | "l1Fee": "0xf94444c1b9", 216 | "l1GasPrice": "0x1a6766f6", 217 | "l1GasUsed": "0xa5d7" 218 | }, 219 | { 220 | "status": "0x1", 221 | "cumulativeGasUsed": "0x78ed07", 222 | "logs": [ 223 | { 224 | "address": "0x1638438ce0960a1f6a139ef87b292c0b62dbb3c3", 225 | "topics": [ 226 | "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", 227 | "0x0000000000000000000000000000000000000000000000000000000000000000", 228 | "0x000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a" 229 | ], 230 | "data": "0x", 231 | "blockHash": "0x39dc835418ab0efdeee76491526b79ac826ea7383163110303259ffc9a09c722", 232 | "blockNumber": "0xbf7251", 233 | "transactionHash": "0x0dd9b34425ab4c6e31dd5debe49a6f167137c90e45d11cd765d62f3b4a417215", 234 | "transactionIndex": "0xa", 235 | "logIndex": "0x94", 236 | "removed": false 237 | } 238 | ], 239 | "logsBloom": "0x00000000000000000000000000000000000000000200000000800000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000000000000000000000000000", 240 | "type": "0x2", 241 | "transactionHash": "0x0dd9b34425ab4c6e31dd5debe49a6f167137c90e45d11cd765d62f3b4a417215", 242 | "transactionIndex": "0xa", 243 | "blockHash": "0x39dc835418ab0efdeee76491526b79ac826ea7383163110303259ffc9a09c722", 244 | "blockNumber": "0xbf7251", 245 | "gasUsed": "0x20f211", 246 | "effectiveGasPrice": "0x18aa5", 247 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 248 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 249 | "contractAddress": null, 250 | "l1BaseFeeScalar": "0x21f9", 251 | "l1BlobBaseFee": "0x167ba504", 252 | "l1BlobBaseFeeScalar": "0xdd3ef", 253 | "l1Fee": "0x1df09bfc3e4", 254 | "l1GasPrice": "0x1a6766f6", 255 | "l1GasUsed": "0x13eb6" 256 | }, 257 | { 258 | "status": "0x1", 259 | "cumulativeGasUsed": "0xea0ad1", 260 | "logs": [ 261 | { 262 | "address": "0xf919250541a98a36eadef0e2f03fe0a9ca707fe3", 263 | "topics": [ 264 | "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", 265 | "0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6", 266 | "0x0000000000000000000000001638438ce0960a1f6a139ef87b292c0b62dbb3c3", 267 | "0x000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a" 268 | ], 269 | "data": "0x", 270 | "blockHash": "0x874d59060a50e79c703f221b23dc67c6faeaace1eac0a2cd685c8eea1c4c2b20", 271 | "blockNumber": "0xbf7253", 272 | "transactionHash": "0xe5857b14806e665d27e75854d3d7f1208906e4a7e4836e00f7df2f4c60051571", 273 | "transactionIndex": "0x11", 274 | "logIndex": "0x1ae", 275 | "removed": false 276 | } 277 | ], 278 | "logsBloom": "0x00000004000000000000000000000000000000000000000020000000040000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000010000000000000000000008000000000001000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000001000000000008000000000000000000000000000000000001000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000", 279 | "type": "0x2", 280 | "transactionHash": "0xe5857b14806e665d27e75854d3d7f1208906e4a7e4836e00f7df2f4c60051571", 281 | "transactionIndex": "0x11", 282 | "blockHash": "0x874d59060a50e79c703f221b23dc67c6faeaace1eac0a2cd685c8eea1c4c2b20", 283 | "blockNumber": "0xbf7253", 284 | "gasUsed": "0xc938", 285 | "effectiveGasPrice": "0x18aa1", 286 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 287 | "to": "0xf919250541a98a36eadef0e2f03fe0a9ca707fe3", 288 | "contractAddress": null, 289 | "l1BaseFeeScalar": "0x21f9", 290 | "l1BlobBaseFee": "0x167ba504", 291 | "l1BlobBaseFeeScalar": "0xdd3ef", 292 | "l1Fee": "0x9e88a4e87", 293 | "l1GasPrice": "0x1a6766f6", 294 | "l1GasUsed": "0x697" 295 | }, 296 | { 297 | "status": "0x1", 298 | "cumulativeGasUsed": "0xe2eeea", 299 | "logs": [], 300 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 301 | "type": "0x2", 302 | "transactionHash": "0x3f8ada3cb78c07698ca5eed3a0a6de63cea9bc5043bb96420fead9363cd6e3d7", 303 | "transactionIndex": "0x15", 304 | "blockHash": "0x2a69045e231e07526fcafbe58acddf3deffc292c9d79a97d3e4f859decb9f1bd", 305 | "blockNumber": "0xbf7256", 306 | "gasUsed": "0x80317", 307 | "effectiveGasPrice": "0x18a9e", 308 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 309 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 310 | "contractAddress": null, 311 | "l1BaseFeeScalar": "0x21f9", 312 | "l1BlobBaseFee": "0x14c8fcf1", 313 | "l1BlobBaseFeeScalar": "0xdd3ef", 314 | "l1Fee": "0x91794ea818", 315 | "l1GasPrice": "0x1c9e3a09", 316 | "l1GasUsed": "0x6601" 317 | }, 318 | { 319 | "status": "0x1", 320 | "cumulativeGasUsed": "0xa9af6d", 321 | "logs": [ 322 | { 323 | "address": "0x600966eafd19b5fc051a1ea4175ea20ff305134b", 324 | "topics": [ 325 | "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", 326 | "0x0ce23c3e399818cfee81a7ab0880f714e53d7672b08df0fa62f2843416e1ea09", 327 | "0x000000000000000000000000f556e738324de1c3169972b44ab4810a59ff58c0", 328 | "0x000000000000000000000000610ac56bd97c7817e787a7d5caf0346c4594037a" 329 | ], 330 | "data": "0x", 331 | "blockHash": "0x919c721de6b26c1df3b1f676414a40454e711620a7eba248279ac4219d97b163", 332 | "blockNumber": "0xbf7258", 333 | "transactionHash": "0x1c1e874f49d0da79f392f74987fe0f9f2143737a85d4d836cf2f2f03acd27bed", 334 | "transactionIndex": "0xa", 335 | "logIndex": "0x124", 336 | "removed": false 337 | } 338 | ], 339 | "logsBloom": "0x00000004000000000000000000000000000000000000000000008000040000000000000000000000000000000008000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000010000000000000000000080000000000010000000000000000000000000000000400000000000001000000004000000000000000000000000000000000000000000000000004100000000000000000000000000000000000000000000000000001000000000000000000000000000", 340 | "type": "0x2", 341 | "transactionHash": "0x1c1e874f49d0da79f392f74987fe0f9f2143737a85d4d836cf2f2f03acd27bed", 342 | "transactionIndex": "0xa", 343 | "blockHash": "0x919c721de6b26c1df3b1f676414a40454e711620a7eba248279ac4219d97b163", 344 | "blockNumber": "0xbf7258", 345 | "gasUsed": "0xc933", 346 | "effectiveGasPrice": "0x18a9e", 347 | "from": "0x610ac56bd97c7817e787a7d5caf0346c4594037a", 348 | "to": "0x600966eafd19b5fc051a1ea4175ea20ff305134b", 349 | "contractAddress": null, 350 | "l1BaseFeeScalar": "0x21f9", 351 | "l1BlobBaseFee": "0x14c8fcf1", 352 | "l1BlobBaseFeeScalar": "0xdd3ef", 353 | "l1Fee": "0x966bf7fd7", 354 | "l1GasPrice": "0x1c9e3a09", 355 | "l1GasUsed": "0x697" 356 | } 357 | ], 358 | "libraries": [], 359 | "pending": [], 360 | "returns": {}, 361 | "timestamp": 1744428937, 362 | "chain": 480, 363 | "commit": "e08397c" 364 | } --------------------------------------------------------------------------------