// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "../AgentIdMembershipVerifier.sol"; import "../vrf/UsdtRoundBootstrapper.sol"; /// @notice Permissionless faucet token for chain97 demos. NOT USDT and has no redemption value. contract TestnetUsdt { string public constant name = "Lottery Test USDT - No Value"; string public constant symbol = "TEST-USDT"; uint8 public constant decimals = 18; uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); constructor() { require(block.chainid == 97, "testnet only"); } function faucet(uint256 amount) external { require(amount > 0 && amount <= 1000 ether, "faucet limit"); totalSupply += amount; balanceOf[msg.sender] += amount; emit Transfer(address(0), msg.sender, amount); } function approve(address spender, uint256 amount) external returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) external returns (bool) { _move(msg.sender, to, amount); return true; } function transferFrom(address from, address to, uint256 amount) external returns (bool) { allowance[from][msg.sender] -= amount; _move(from, to, amount); return true; } function _move(address from, address to, uint256 amount) private { require(to != address(0), "recipient"); balanceOf[from] -= amount; balanceOf[to] += amount; emit Transfer(from, to, amount); } } /// @notice Open test membership, NOT Binance Agent ID. No official identity attestation. contract TestnetAgentId { mapping(address => uint256) public balanceOf; event TestIdentityClaimed(address indexed account); constructor() { require(block.chainid == 97, "testnet only"); } function claim() external { require(balanceOf[msg.sender] == 0, "already claimed"); balanceOf[msg.sender] = 1; emit TestIdentityClaimed(msg.sender); } } /// @notice One atomic chain97-only deployment; exposes addresses, no management entry points. contract TestnetLotteryBundle { address public immutable stable; address public immutable identity; address public immutable verifier; address public immutable bootstrapper; address public immutable adapter; address public immutable round; constructor(address treasury, uint256 saleDeadline, uint256 drawDeadline) { require(block.chainid == 97, "testnet only"); stable = address(new TestnetUsdt()); identity = address(new TestnetAgentId()); verifier = address(new AgentIdMembershipVerifier(identity, 97)); UsdtLotteryRound.Config memory cfg = UsdtLotteryRound.Config({ stable: stable, verifier: verifier, randomness: address(0), treasury: treasury, saleDeadline: saleDeadline, drawDeadline: drawDeadline }); ImmutableVrfAdapter.Config memory oracle = ImmutableVrfAdapter.Config({ coordinator: 0xDA3b641D438362C440Ac5458c57e00a712b66700, keyHash: 0x8596b430971ac45bdf6088665b9ad8e8630c9d5049ab54b14dff711bee7c0e26, confirmations: 3, callbackGasLimit: 200000, nativePayment: true }); UsdtRoundBootstrapper deployed = new UsdtRoundBootstrapper(cfg, oracle); bootstrapper = address(deployed); adapter = deployed.adapter(); round = deployed.round(); } }