CORE CONCEPTS

Smart Contracts

PoP Contract (Solidity Sketch)

1// SPDX-License-Identifier: MIT
2pragma solidity^0.8.24;
3
4import {MerkleProof} from "./MerkleProof.sol";
5
6contract ChainTickPoP {
7    struct CommitMeta {
8        uint32 pairId;        // compact ids reduce gas
9        uint16 timeframeId;   // e.g., 5m=1, 15m=2, 1h=3
10        uint16 modelId;       // versioned model
11        address publisher;    // EOA or contract
12        uint64 seq;          // per-publisher sequence
13        uint40 minRevealAt;  // unix seconds
14        uint40 maxRevealAt;  // unix seconds
15    }
16
17    struct CommitRec {
18        bytes32 hashOrRoot;  // single leaf hash or merkle root
19        CommitMeta meta;
20        bool isBatch;
21    }
22
23    event Committed(bytes32 indexed key, bytes32 hashOrRoot, 
24                   CommitMeta meta, bool isBatch);
25    event Revealed(bytes32 indexed key, bytes32 leafHash, 
26                  bytes payloadBytesOrCID);
27
28    mapping(bytes32 => CommitRec) public commits;
29
30    function commit(bytes32 leafHash, CommitMeta calldata meta) external {
31        bytes32 k = _key(meta);
32        require(commits[k].hashOrRoot == bytes32(0), "exists");
33        commits[k] = CommitRec(leafHash, meta, false);
34        emit Committed(k, leafHash, meta, false);
35    }
36    
37    function revealSingle(
38        CommitMeta calldata meta,
39        bytes calldata canonicalPayloadNoNonce,
40        bytes32 nonce,
41        bytes calldata payloadBytesOrCID
42    ) external {
43        bytes32 k = _key(meta);
44        CommitRec memory rec = commits[k];
45        require(!rec.isBatch, "batch");
46        require(block.timestamp >= rec.meta.minRevealAt && 
47                block.timestamp <= rec.meta.maxRevealAt, "window");
48        
49        bytes32 computed = keccak256(bytes.concat(canonicalPayloadNoNonce, nonce));
50        require(computed == leafHash, "leaf mismatch");
51        emit Revealed(k, computed, payloadBytesOrCID);
52    }
53
54    function revealLeaf(
55        CommitMeta calldata meta,
56        bytes calldata canonicalPayloadNoNonce,
57        bytes32 nonce,
58        bytes32 leafHash,
59        bytes32[] calldata proof,
60        bytes calldata payloadBytesOrCID
61    ) external {
62        bytes32 k = _key(meta);
63        CommitRec memory rec = commits[k];
64        require(rec.isBatch, "single");
65        require(block.timestamp >= rec.meta.minRevealAt && 
66                block.timestamp <= rec.meta.maxRevealAt, "window");
67        
68        bytes32 computed = keccak256(bytes.concat(canonicalPayloadNoNonce, nonce));
69        require(computed == leafHash, "leaf mismatch");
70        require(MerkleProof.verify(proof, rec.hashOrRoot, leafHash), "badproof");
71        emit Revealed(k, computed, payloadBytesOrCID);
72    }
73}
Notes: Store payloads as event bytes or IPFS CIDs to keep on-chain storage lean. A separate indexer flags Verified/Expired.

Buyback & Burn Module

1// PSEUDOCODE — audit before mainnet
2pragma solidity^0.8.24;
3
4interface IERC20 {
5    function transferFrom(address,address,uint256) external returns(bool);
6    function balanceOf(address) external view returns(uint256);
7    function transfer(address,uint256) external returns(bool);
8}
9
10interface IRouter {/* swapExactTokensForTokens, etc. */}
11
12contract BuybackBurn {
13    IERC20 public usdc; IERC20 public ctick; IRouter public router;
14    address public burnAddr; uint256 public maxSlippageBps; // e.g., 50 = 0.5%
15
16    event Funded(uint256 amount);
17    event Buyback(uint256 usdcSpent, uint256 ctickBought);
18    event Burned(uint256 ctickAmount);
19
20    function fund(uint256 amt) external {
21        /* treasury funds USDC/USDT */
22        emit Funded(amt);
23    }
24
25    function executeTWAP(uint256 chunks, uint256 minOut) external {
26        /* keeper-scheduled swaps */
27    }
28
29    function burnAll() external {
30        uint256 bal = ctick.balanceOf(address(this));
31        ctick.transfer(burnAddr, bal);
32        emit Burned(bal);
33    }
34}

Staking & Slashing Primitives

  • Strategy providers stake CTICK to list; violating PoP rules (missed reveal, payload mismatch) or spam triggers slashing.
  • Slashed CTICK: portion burned, portion to insurance/treasury.

Deployment & Addresses

  • Network: Arbitrum One (mainnet) and Arbitrum Sepolia (testnet).
  • Addresses: Will be published post-audit. Example placeholders:
  • PoP: 0xPOP...
  • BuybackBurn 0xBBB...