Deploy.s.sol
Foundry deployment script: wires the whole system together in dependency order.
192 lines8.2 KBSolidity
| 1 | // SPDX-License-Identifier: MIT |
| 2 | pragma solidity ^0.8.24; |
| 3 | |
| 4 | import {Script, console2} from "forge-std/Script.sol"; |
| 5 | |
| 6 | import {K401} from "../src/K401.sol"; |
| 7 | import {K401Treasury} from "../src/K401Treasury.sol"; |
| 8 | import {K401Oracle} from "../src/K401Oracle.sol"; |
| 9 | import {K401Distributor} from "../src/K401Distributor.sol"; |
| 10 | import {K401Staking} from "../src/K401Staking.sol"; |
| 11 | import {K401SeatRegistry} from "../src/K401SeatRegistry.sol"; |
| 12 | import {K401Seat6551, K401Seat6551Account} from "../src/K401Seat6551.sol"; |
| 13 | import {ERC6551Registry} from "../src/ERC6551Registry.sol"; |
| 14 | import {K401FeeSplitter} from "../src/K401FeeSplitter.sol"; |
| 15 | import {K401StockDesk} from "../src/K401StockDesk.sol"; |
| 16 | import {K401BondDepository} from "../src/K401BondDepository.sol"; |
| 17 | import {K401Buyback} from "../src/K401Buyback.sol"; |
| 18 | import {K401Lens} from "../src/K401Lens.sol"; |
| 19 | |
| 20 | /** |
| 21 | * @notice Full ordered deployment + wiring for $401K "The Firm". |
| 22 | * |
| 23 | * Required env: |
| 24 | * PRIVATE_KEY deployer key |
| 25 | * USDG USDG token address |
| 26 | * K401_USDG_PAIR canonical 401K/USDG UniV2 pair (must already exist and be seeded) |
| 27 | * ROUTER UniV2-compatible router |
| 28 | * Optional env: |
| 29 | * OWNER protocol owner (default: deployer) |
| 30 | * TEAM team fee receiver (default: deployer) |
| 31 | * LP_RECEIVER POL receiver (default: OWNER) |
| 32 | * INITIAL_SUPPLY initial 401K supply, wei (default: 0) |
| 33 | * SUPPLY_OWNER initial supply recipient (default: deployer) |
| 34 | * ERC6551_REGISTRY existing ERC-6551 registry (default: deploy a fresh one) |
| 35 | * POL_MANAGER address allowed to move 401K in/out of the pair fee-free (POL ops). |
| 36 | * Leave unset and the deployer pays the normal 5% when seeding liquidity; |
| 37 | * that fee is not lost, it just routes through the FeeSplitter. |
| 38 | * |
| 39 | * The pair MUST exist before running this script: the oracle binds to it immutably. |
| 40 | */ |
| 41 | contract Deploy is Script { |
| 42 | struct Deployment { |
| 43 | address k401; |
| 44 | address mirror; |
| 45 | address treasury; |
| 46 | address oracle; |
| 47 | address staking; |
| 48 | address registry; |
| 49 | address distributor; |
| 50 | address erc6551Registry; |
| 51 | address seatAccountImpl; |
| 52 | address seat6551; |
| 53 | address stockDesk; |
| 54 | address feeSplitter; |
| 55 | address bonds; |
| 56 | address buyback; |
| 57 | address lens; |
| 58 | } |
| 59 | |
| 60 | function run() external returns (Deployment memory d) { |
| 61 | uint256 pk = vm.envUint("PRIVATE_KEY"); |
| 62 | address deployer = vm.addr(pk); |
| 63 | |
| 64 | address usdg = vm.envAddress("USDG"); |
| 65 | address pair = vm.envAddress("K401_USDG_PAIR"); |
| 66 | address router = vm.envAddress("ROUTER"); |
| 67 | address owner = vm.envOr("OWNER", deployer); |
| 68 | address team = vm.envOr("TEAM", deployer); |
| 69 | address lpReceiver = vm.envOr("LP_RECEIVER", owner); |
| 70 | uint256 initialSupply = vm.envOr("INITIAL_SUPPLY", uint256(0)); |
| 71 | address supplyOwner = vm.envOr("SUPPLY_OWNER", deployer); |
| 72 | address existing6551 = vm.envOr("ERC6551_REGISTRY", address(0)); |
| 73 | address polManager = vm.envOr("POL_MANAGER", address(0)); |
| 74 | |
| 75 | vm.startBroadcast(pk); |
| 76 | |
| 77 | // 1. Token (deployer must stay owner until wiring is done). |
| 78 | K401 k401 = new K401(uint96(initialSupply), supplyOwner, deployer); |
| 79 | d.k401 = address(k401); |
| 80 | d.mirror = k401.mirrorERC721(); |
| 81 | |
| 82 | // 2. Reserve + pricing. |
| 83 | K401Treasury treasury = new K401Treasury(address(k401), usdg, deployer); |
| 84 | K401Oracle oracle = new K401Oracle(pair, address(k401), usdg); |
| 85 | d.treasury = address(treasury); |
| 86 | d.oracle = address(oracle); |
| 87 | |
| 88 | // 3. Game layer + staking + emission. |
| 89 | K401SeatRegistry registry = new K401SeatRegistry(address(k401), deployer); |
| 90 | K401Staking staking = new K401Staking(address(k401), address(registry), deployer); |
| 91 | K401Distributor distributor = |
| 92 | new K401Distributor(address(k401), address(oracle), address(treasury), address(staking), deployer); |
| 93 | d.registry = address(registry); |
| 94 | d.staking = address(staking); |
| 95 | d.distributor = address(distributor); |
| 96 | |
| 97 | // 4. ERC-6551. |
| 98 | address erc6551Registry = existing6551; |
| 99 | if (erc6551Registry == address(0)) erc6551Registry = address(new ERC6551Registry()); |
| 100 | K401Seat6551Account impl = new K401Seat6551Account(); |
| 101 | K401Seat6551 seat6551 = new K401Seat6551(erc6551Registry, address(impl), d.mirror); |
| 102 | d.erc6551Registry = erc6551Registry; |
| 103 | d.seatAccountImpl = address(impl); |
| 104 | d.seat6551 = address(seat6551); |
| 105 | |
| 106 | // 5. Revenue plumbing. |
| 107 | K401StockDesk stockDesk = |
| 108 | new K401StockDesk(usdg, address(oracle), address(registry), address(seat6551), deployer); |
| 109 | K401FeeSplitter splitter = new K401FeeSplitter(address(k401), usdg, deployer); |
| 110 | K401BondDepository bonds = |
| 111 | new K401BondDepository(address(k401), address(oracle), address(treasury), deployer); |
| 112 | K401Buyback buyback = new K401Buyback(address(k401), usdg, address(treasury), address(oracle), deployer); |
| 113 | d.stockDesk = address(stockDesk); |
| 114 | d.feeSplitter = address(splitter); |
| 115 | d.bonds = address(bonds); |
| 116 | d.buyback = address(buyback); |
| 117 | |
| 118 | // 6. Wiring — K401. |
| 119 | k401.setSeatRegistry(address(registry)); |
| 120 | k401.setStaking(address(staking)); |
| 121 | k401.setFeeSplitter(address(splitter)); |
| 122 | k401.mapPair(pair, true); |
| 123 | k401.setWhitelist(address(staking), true); |
| 124 | k401.setWhitelist(address(treasury), true); |
| 125 | k401.setWhitelist(address(stockDesk), true); |
| 126 | k401.setWhitelist(address(bonds), true); |
| 127 | k401.setWhitelist(address(buyback), true); |
| 128 | k401.setWhitelist(address(distributor), true); |
| 129 | // Optional: a protocol-owned-liquidity manager that moves 401K into the pair fee-free. |
| 130 | // NOTE: whitelisting is permanent. Only ever point this at a contract you control. |
| 131 | if (polManager != address(0)) k401.setWhitelist(polManager, true); |
| 132 | k401.addMinter(address(treasury)); |
| 133 | k401.addMinter(address(distributor)); |
| 134 | k401.addBurner(address(registry)); |
| 135 | k401.addBurner(address(buyback)); |
| 136 | |
| 137 | // 7. Wiring — modules. |
| 138 | registry.setStaking(address(staking)); |
| 139 | registry.setStockDesk(address(stockDesk)); |
| 140 | staking.setDistributor(address(distributor)); |
| 141 | treasury.addDepositor(address(bonds)); |
| 142 | treasury.addPolToken(pair); |
| 143 | stockDesk.setRouter(router); |
| 144 | splitter.wire(router, address(stockDesk), address(treasury), lpReceiver, address(buyback), team); |
| 145 | |
| 146 | // 8. Lens. |
| 147 | K401Lens lens = new K401Lens( |
| 148 | address(k401), |
| 149 | address(treasury), |
| 150 | address(oracle), |
| 151 | address(distributor), |
| 152 | address(staking), |
| 153 | address(registry), |
| 154 | address(seat6551), |
| 155 | address(stockDesk), |
| 156 | address(bonds) |
| 157 | ); |
| 158 | d.lens = address(lens); |
| 159 | |
| 160 | // 9. Hand ownership over, if requested. |
| 161 | if (owner != deployer) { |
| 162 | k401.transferOwnership(owner); |
| 163 | treasury.transferOwnership(owner); |
| 164 | registry.transferOwnership(owner); |
| 165 | staking.transferOwnership(owner); |
| 166 | distributor.transferOwnership(owner); |
| 167 | stockDesk.transferOwnership(owner); |
| 168 | splitter.transferOwnership(owner); |
| 169 | bonds.transferOwnership(owner); |
| 170 | buyback.transferOwnership(owner); |
| 171 | } |
| 172 | |
| 173 | vm.stopBroadcast(); |
| 174 | |
| 175 | console2.log("K401 ", d.k401); |
| 176 | console2.log("Mirror (ERC721) ", d.mirror); |
| 177 | console2.log("Treasury ", d.treasury); |
| 178 | console2.log("Oracle ", d.oracle); |
| 179 | console2.log("SeatRegistry ", d.registry); |
| 180 | console2.log("Staking ", d.staking); |
| 181 | console2.log("Distributor ", d.distributor); |
| 182 | console2.log("ERC6551Registry ", d.erc6551Registry); |
| 183 | console2.log("SeatAccountImpl ", d.seatAccountImpl); |
| 184 | console2.log("Seat6551 ", d.seat6551); |
| 185 | console2.log("StockDesk ", d.stockDesk); |
| 186 | console2.log("FeeSplitter ", d.feeSplitter); |
| 187 | console2.log("BondDepository ", d.bonds); |
| 188 | console2.log("Buyback ", d.buyback); |
| 189 | console2.log("Lens ", d.lens); |
| 190 | } |
| 191 | } |
| 192 |
Click any line number to deep-link to it — the target line highlights on load.