Skill: planetai87/warren-nft-mainnet (version 1.0.8)

--- name: warren-nft description: Deploy NFT collections permanently on MegaETH mainnet. Images are stored on-chain via SSTORE2, then published through WarrenContainer and WarrenLaunchedNFT. metadata: {"openclaw":{"emoji":"🖼️","homepage":"https://thewarren.app","source":"https://github.com/planetai87/warren-tools","requires":{"anyBins":["node"],"env":["PRIVATE_KEY"]},"primaryEnv":"PRIVATE_KEY"}} user-invocable: true --- # Warren NFT - On-Chain NFT Collection Deployment Deploy complete NFT collections with permanent on-chain image storage on MegaETH mainnet. **Network**: MegaETH Mainnet (Chain ID: 4326) **RPC**: `https://mainnet.megaeth.com/rpc` **Explorer**: https://megaeth.blockscout.com ## How It Works ``` Your Images → SSTORE2 (on-chain) → WarrenContainer → WarrenLaunchedNFT /images/1.png tokenURI renders /images/2.png images on-chain ... ``` 1. Each image is deployed as a Page contract (fractal tree for larger files). 2. All images are stored in a WarrenContainer NFT at `/images/1.png`, `/images/2.png`, etc. 3. A WarrenLaunchedNFT contract is deployed referencing the container. 4. Collection is registered for management and mint pages. ## Setup (One Time) ```bash cd {baseDir} bash setup.sh ``` ## Prerequisites ### 1. Wallet + MegaETH ETH Bridge ETH from Ethereum to MegaETH mainnet for gas. Approximate cost: - ~0.03 ETH for a small collection (around 10 images) ### 2. Genesis Access Requirement The script checks in this order: 1. Human Genesis Key (0xRabbitNeo) 2. 0xRabbit.agent Key 3. Auto-mint 0xRabbit.agent Key (free) Default `RABBIT_AGENT_ADDRESS`: [REDACTED_SECRET] (override via env). If you override or unset it, mint a human key: - https://thewarren.app/mint ## Contract Addresses (Mainnet) | Contract | Address | |----------|---------| | Genesis Key NFT (0xRabbitNeo) | [REDACTED_SECRET] | | 0xRabbit.agent Key NFT | [REDACTED_SECRET] | | WarrenContainer | [REDACTED_SECRET] | | WarrenContainerRenderer | [REDACTED_SECRET] | | Treasury/Relayer | [REDACTED_SECRET] | ## Environment Variables | Variable | Required | Default | Purpose | |----------|----------|---------|---------| | `PRIVATE_KEY` | **Yes** | — | Wallet private key for signing transactions | | `RPC_URL` | No | `https://mainnet.megaeth.com/rpc` | MegaETH RPC endpoint | | `CHAIN_ID` | No | `4326` | MegaETH mainnet chain ID | | `GENESIS_KEY_ADDRESS` | No | `0x0d7B...5a88` | Genesis Key NFT contract | | `RABBIT_AGENT_ADDRESS` | No | `0x3f0C...61f2` | 0xRabbit.agent NFT contract | | `CONTAINER_ADDRESS` | No | `0x6517...5964` | WarrenContainer contract | | `RENDERER_ADDRESS` | No | `0xdC0c...6BB` | WarrenContainerRenderer contract | | `TREASURY_ADDRESS` | No | `0xcea9...8c550` | Treasury/relayer address | | `REGISTER_API` | No | `https://thewarren.app/api/container-nfts` | Collection registration endpoint (see Security) | | `CHUNK_SIZE` | No | `15000` | Bytes per chunk (15KB) | | `GROUP_SIZE` | No | `500` | Max addresses per tree node | ## Deploy NFT Collection ### Option 1: From Image Folder ```bash cd {baseDir} PRIVATE_KEY=0x... node deploy-nft.js \ --images-folder ./my-art/ \ --name "Cool Robots" \ --symbol "ROBOT" \ --description "100 unique robot NFTs on-chain" \ --max-supply 100 ``` ### Option 2: Auto-Generate SVG Art ```bash cd {baseDir} PRIVATE_KEY=0x... node deploy-nft.js \ --generate-svg 10 \ --name "Generative Art" \ --symbol "GART" \ --description "AI-generated on-chain art" ``` ### Full Configuration ```bash PRIVATE_KEY=0x... node deploy-nft.js \ --images-folder ./collection/ \ --name "Cyber Punks" \ --symbol "CPUNK" \ --description "On-chain cyberpunk collection" \ --max-supply 1000 \ --whitelist-price 0.01 \ --public-price 0.02 \ --max-per-wallet 5 \ --royalty-bps 500 ``` ## CLI Options | Option | Required | Default | Description | |--------|----------|---------|-------------| | `--images-folder <path>` | * | - | Folder with image files | | `--generate-svg <count>` | * | - | Generate random SVG art (1-256) | | `--name <string>` | Yes | - | Collection name | | `--symbol <string>` | Yes | - | Collection symbol (3-5 chars) | | `--description <text>` | No | Auto | Collection description | | `--max-supply <number>` | No | Image count | Maximum mintable NFTs | | `--whitelist-price <eth>` | No | 0 | Whitelist mint price in ETH | | `--public-price <eth>` | No | 0 | Public mint price in ETH | | `--max-per-wallet <number>` | No | 10 | Mint limit per wallet | | `--royalty-bps <number>` | No | 500 | Royalty (500 = 5%, max 1000 = 10%) | \* Either `--images-folder` or `--generate-svg` is required. ## Output ``` NFT Collection Deployed! NFT Contract: 0xABC... Container ID: 15 Image Count: 10 Max Supply: 100 Public Price: 0 ETH (Free) Management: https://thewarren.app/launchpad/0xABC.../ Mint Page: https://thewarren.app/launchpad/0xABC.../mint ``` ## Image Requirements - Formats: PNG, JPG, JPEG, SVG, GIF, WebP - Size: up to 500KB per image - Count: 1-256 images per collection - Naming: sequential or alphabetical ## Example Workflows ### Quick Test (3 SVGs) ```bash cd {baseDir} PRIVATE_KEY=0x... node deploy-nft.js --generate-svg 3 --name "Quick Test" --symbol "QT" ``` ### Medium Test (20 SVGs) ```bash cd {baseDir} PRIVATE_KEY=0x... node deploy-nft.js --generate-svg 20 --name "Art Collection" --symbol "ART" --public-price 0.001 ``` ### Full Collection (100 SVGs) ```bash cd {baseDir} PRIVATE_KEY=0x... node deploy-nft.js --generate-svg 100 --name "Century" --symbol "C100" --max-per-wallet 3 ``` ## Troubleshooting **"No ETH balance"** - Bridge ETH to MegaETH mainnet. **"No Genesis Key found and RABBIT_AGENT_ADDRESS is not configured"** - Set [REDACTED_SECRET], or mint human key at `https://thewarren.app/mint`. **"Image exceeds 500KB"** - Resize or compress images. **"Too many images"** - Maximum 256 images per container. **DB registration warning** - Non-critical. Collection is still deployed on-chain. ## Notes - Mainnet content is permanent and immutable. - You pay gas from your own wallet. ## Security & Privacy - **No data exfiltration**: Images are sent only as blockchain transactions to the configured RPC endpoint. - **PRIVATE_KEY handling**: Used solely to sign transactions. Never logged, stored on disk, or transmitted to third parties. - **Network endpoints**: Only the configured `RPC_URL` (default: `mainnet.megaeth.com/rpc`) and `REGISTER_API`. - **REGISTER_API**: After on-chain deployment is complete, the script POSTs collection metadata (name, symbol, maxSupply, prices, NFT contract address, container ID) to `thewarren.app/api/container-nfts` for management page registration. This is **optional and non-critical** — the on-chain collection works without it. No images or private keys are sent. Override with `REGISTER_API` env var or set to empty to disable. - **File access**: Reads only files in the specified `--images-folder`. No access outside that directory. - **No telemetry**: No analytics, tracking, or usage reporting.

path: setup.sh
content: #!/bin/bash
set -euo pipefail
# Warren NFT Deploy - Quick Setup
cd "$(dirname "$0")"
npm init -y > /dev/null 2>&1
npm install ethers
echo ""
echo "✅ Setup complete!"
echo ""
echo "Deploy NFT collection:"
echo "  PRIVATE_KEY=0x... node deploy-nft.js --generate-svg 10 --name 'My NFT' --symbol 'MNFT'"
echo ""
echo "Prerequisites:"
echo "  1. Get MegaETH mainnet ETH via official bridge"
echo "  2. 0xRabbit.agent Key auto-mints (free)"


path: page_bytecode.js
content: /**
 * Page.sol compiled EVM bytecode (Solidity 0.8.26, Cancun EVM, viaIR)
 *
 * Source: foundry-app/src/Page.sol
 * Compiler: solc 0.8.26+commit.8a97fa7a
 * Verified on: https://megaeth.blockscout.com
 *
 * SSTORE2 Page contract - stores arbitrary data as immutable contract bytecode.
 * Contains no external calls, no selfdestruct, no delegatecall.
 *
 * To reproduce: cd foundry-app && forge build
 * Then: cat out/Page.sol/Page.json | jq -r .bytecode.object
 */
module.exports = '0x60a0604052346100e45761025c80380380610019816100fc565b9283398101906020818303126100e4578051906001600160401b0382116100e4570181601f820112156100e4578051906001600160401b0382116100e85761006a601f8301601f19166020016100fc565b92828452602083830101116100e457815f9260208093018386015e8301015280518060401b6bfe61000180600a3d393df3000161fffe8211830152600b8101601583015ff09182156100d7575260805260405161013a908161012282396080518181816044015260d50152f35b63301164255f526004601cfd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b6040519190601f01601f191682016001600160401b038111838210176100e85760405256fe6080806040526004361015610012575f80fd5b5f3560e01c9081634822da1c146100c357506357de26a414610032575f80fd5b346100bf575f3660031901126100bf577f00000000000000000000000000000000000000000000000000000000000000006020608060405180935f19813b0164ffffffffff16905f6021830191601f8501903c808252016040810193846040528385528051938491826060850152018383015e5f828483010152603f1992601f8019910116810103010190f35b5f80fd5b346100bf575f3660031901126100bf577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f3fea2646970667358221220fe4f8a378a0b003d3e1438e45234630293b1a4f7cf94a9f28a4c2d2531789b9d64736f6c634300081a0033';


path: WarrenLaunchedNFT.bytecode.json
content: {
  "contractName": "WarrenLaunchedNFT",
  "compiler": "solc 0.8.26+commit.8a97fa7a",
  "evmVersion": "cancun",
  "optimization": {
    "enabled": true,
    "mode": "viaIR"
  },
  "source": "foundry-app/src/WarrenLaunchedNFT.sol",
  "verified": "https://megaeth.blockscout.com",
  "bytecode": "0x6080604052346105e957613ed180380380610019816105ed565b92833981016101c0828203126105e95761003282610612565b91602081015191604082015160018060401b0381116105e95781610057918401610626565b60608301519091906001600160401b0381116105e95781610079918501610626565b608084015190916001600160401b0382116105e957610099918501610626565b60a084015160c085015160e08601519161010087015193610120880151956100c46101408a01610612565b976101608a01519a60018060601b038c169c8d8d036105e9576100f76101a06100f06101808f01610612565b9d01610612565b6001600160a01b03909c169d8e156105da576001600160a01b038d169081156105da576103e8106105cb5780638b78c6d819555f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3600180546001600160a01b03199081163317909155600280549091166001600160a01b03929092169190911790556003558051906001600160401b0382116104025760045490600182811c921680156105c1575b60208310146103e45781601f849311610553575b50602090601f83116001146104ed575f926104e2575b50508160011b915f199060031b1c1916176004555b8051906001600160401b0382116104025760055490600182811c921680156104d8575b60208310146103e45781601f849311610487575b50602090601f8311600114610421575f92610416575b50508160011b915f199060031b1c1916176005555b8051906001600160401b0382116104025760065490600182811c921680156103f8575b60208310146103e45781601f849311610376575b50602090601f8311600114610310575f92610305575b50508160011b915f199060031b1c1916176006555b600855600955600a55600d55600c556001600160a01b0381166102fd5750905b60018060a01b03199060a01b169060018060a01b03161760105560018060a01b03195f5416175f5560405161385990816106788239f35b9050906102c6565b015190505f80610291565b60065f9081528281209350601f198516905b81811061035e5750908460019594939210610346575b505050811b016006556102a6565b01515f1960f88460031b161c191690555f8080610338565b92936020600181928786015181550195019301610322565b60065f529091507ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f601f840160051c810191602085106103da575b90601f859493920160051c01905b8181106103cc575061027b565b5f81558493506001016103bf565b90915081906103b1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610267565b634e487b7160e01b5f52604160045260245ffd5b015190505f8061022f565b60055f9081528281209350601f198516905b81811061046f5750908460019594939210610457575b505050811b01600555610244565b01515f1960f88460031b161c191690555f8080610449565b92936020600181928786015181550195019301610433565b90915060055f5260205f20601f840160051c810191602085106104ce575b90601f859493920160051c01905b8181106104c05750610219565b5f81558493506001016104b3565b90915081906104a5565b91607f1691610205565b015190505f806101cd565b60045f9081528281209350601f198516905b81811061053b5750908460019594939210610523575b505050811b016004556101e2565b01515f1960f88460031b161c191690555f8080610515565b929360206001819287860151815501950193016104ff565b60045f529091507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f840160051c810191602085106105b7575b90601f859493920160051c01905b8181106105a957506101b7565b5f815584935060010161059c565b909150819061058e565b91607f16916101a3565b63e0e54ced60e01b5f5260045ffd5b63d92e233d60e01b5f5260045ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761040257604052565b51906001600160a01b03821682036105e957565b81601f820112156105e9578051906001600160401b03821161040257610655601f8301601f19166020016105ed565b92828452602083830101116105e957815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714612616575080630561942a146125fc57806305fefda7146125ae57806306fdde031461067e578063081812fc1461255d578063095ea7b3146124b557806318160ddd1461249857806323b872dd14612486578063252cc1271461244957806325692962146124005780632a55205a146123c35780632db11544146123195780632e943fbd146122fc5780632eb4a7ab146122df5780632f39352a146117705780633a602b4d146122a75780633ccfd60b1461224f5780633dca40e61461223357806342842e0e146121fa57806342bbb4a914612191578063453c231014612174578063484b973c146121105780634a18ae0e1461201357806352bc22c914611f9b578063539aa77f14611f8057806354d1f13d14611f3c5780635514a4a814611d7d57806356d3163d14611d1557806359efd18614611c0b5780635a23dd9914611b9257806361d027b314611b6b5780636352211e14611b1557806364d0764e14611aea5780636c3e51bd14611a8f5780636f33a00314611a415780636fb7279514611a1757806370a08231146119c4578063715018a61461197b5780637cb647591461192857806387cd56a2146118d95780638967cca9146118865780638ada6b0f1461185e5780638da5cb5b146118325780638f2fc60b1461178b57806395d89b411461177057806399331dc8146116f55780639fbc8713146116cd578063a22cb46514611671578063a945bf8014611654578063b88d4fde146115ea578063c051e38a146115ca578063c4d0f3f714611234578063c63adb2b14611214578063c87b56dd14610bf4578063cb039e8f14610a7d578063d2cab05614610930578063d441a0c3146107e5578063d5abeb01146107c8578063d5f39488146107a0578063e1a4521814610784578063e268e4d314610763578063e2c6875c14610699578063e5326ab11461067e578063e575a50c14610640578063e985e9c5146105fc578063f04e283e146105af578063f0f44260146104fa578063f11cb0af14610494578063f2fde38b14610457578063fa485ab4146103e4578063fc1a1c36146103c7578063fc8a247e146103755763fee81cf41461033f575f80fd5b34610371576020366003190112610371576103586126b6565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b34610371576103833661267c565b905f52601260205260405f20908154811015610371576103a96103af916103c393612a48565b9061294c565b604051918291602083526020830190612692565b0390f35b34610371575f366003190112610371576020600954604051908152f35b34610371576040366003190112610371576024356001600160401b0381116103715736602382011215610371576103af60208061042e6103c3943690602481600401359101612a78565b6004355f526011825260405f20604051938285935191829101845e8201908152030190206128ae565b60203660031901126103715761046b6126b6565b610473613207565b8060601b1561048757610485906133db565b005b637448fbae5f526004601cfd5b346103715760203660031901126103715760043560ff8116809103610371576104bb613207565b600b547f531024911d0c899e184bad3c764b300ecba05832e3d3b191238243b6c9ba55186040805160ff84168152846020820152a160ff191617600b55005b34610371576020366003190112610371576001600160a01b0361051b6126b6565b1680156105a0575f546001600160a01b0381163381900361056b5782907f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a5f80a36001600160a01b031916175f55005b60405162461bcd60e51b815260206004820152600d60248201526c4f6e6c7920747265617375727960981b6044820152606490fd5b63d92e233d60e01b5f5260045ffd5b6020366003190112610371576105c36126b6565b6105cb613207565b63389a75e1600c52805f526020600c2090815442116105ef575f61048592556133db565b636f5e88185f526004601cfd5b34610371576040366003190112610371576106156126b6565b61061d6126cc565b601c52670a5a2e7a000000006008525f5260206030600c20546040519015158152f35b3461037157602036600319011261037157606063ffffffff60ff610665600435613128565b9193906040519415158552166020840152166040820152f35b34610371575f366003190112610371576103c36103af612775565b34610371575f366003190112610371576040515f6006546106b98161271c565b808452906001811690811561073f57506001146106e1575b6103c3836103af81850382612754565b60065f9081527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f939250905b808210610725575090915081016020016103af6106d1565b91926001816020925483858801015201910190929161070d565b60ff191660208086019190915291151560051b840190910191506103af90506106d1565b346103715760203660031901126103715761077c613207565b600435600d55005b34610371575f3660031901126103715760206040516127108152f35b34610371575f366003190112610371576001546040516001600160a01b039091168152602090f35b34610371575f366003190112610371576020600854604051908152f35b34610371576020366003190112610371576004356001600160401b03811161037157610815903690600401612a18565b61081d613207565b6013545f601355806108a5575b505f5b81811061083657005b610841818385612fb3565b601392919254600160401b8110156108915780600161086592016013556013612a48565b91909161087e5760019361087892612e72565b0161082d565b634e487b7160e01b5f525f60045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b60135f525f805160206137e4833981519152015f805160206137e48339815191525b8181106108d4575061082a565b806108e16001925461271c565b806108ee575b50016108c7565b601f8111831461090357505f81555b856108e7565b61091f90825f5283601f60205f20920160051c82019101612e5c565b805f525f60208120818355556108fd565b6040366003190112610371576004356024356001600160401b0381116103715761095e903690600401612a18565b90600160ff600b541603610a6e5761097883600754612bf2565b60085410610a5f5761098c83600954612bcb565b3410610a5057335f52600e6020526109a88360405f2054612bf2565b600d5410610a41576109e8916109e360405160208101903360601b8252601481526109d4603482612754565b51902092600c54923691613004565b613390565b15610a3257335f52600e60205260405f20610a04828254612bf2565b90555f5b818110610a1157005b600190610a2c610a22600754612bff565b8060075533613223565b01610a08565b63582f497d60e11b5f5260045ffd5b63c0e54d7360e01b5f5260045ffd5b63cd1c886760e01b5f5260045ffd5b63d05cb60960e01b5f5260045ffd5b63b980d98b60e01b5f5260045ffd5b34610371576060366003190112610371576004356001600160401b03811161037157610aad903690600401612a18565b6024356001600160401b03811161037157610acc903690600401612a18565b906044356001600160401b03811161037157610aec903690600401612a18565b638b78c6d819549192916001600160a01b031633148015610be0575b610b1190612e1f565b610b1c8486146130ae565b610b278186146130ae565b5f5b858110610b3257005b80610bb7610b43600193898b612ff4565b35610b4f838988612fb3565b6020610b5f86898c969596612fb3565b949093805f5260118352610b8a60405f2084604051809288878337888201908152030190205461271c565b1580610bd7575b610bbd575b5f526011825260405f20836040519485938437820190815203019020612e72565b01610b29565b805f5260128352610bd2848360405f20612f63565b610b96565b50851515610b91565b506001546001600160a01b03163314610b08565b34610371576020366003190112610371576004355f818152673ec412a9852d173d60c11b601c5260209020810181015460601b1561120557610c358161345f565b906020610d256001603f610c488561334b565b605a85610c5660035461334b565b6040519788947f5b7b2274726169745f74797065223a22546f6b656e204944222c22646973706c828701527f61795f74797065223a226e756d626572222c2276616c7565223a00000000000060408701528051918291018587015e8401907f7d2c7b2274726169745f74797065223a22436f6e7461696e6572204944222c22848301527f646973706c61795f74797065223a226e756d626572222c2276616c7565223a00607a830152805192839101609983015e0101607d60f81b838201520301601e19810184520182612754565b815f52601260205260405f208054610d3c81612e08565b91610d4a6040519384612754565b81835260208301905f5260205f205f915b8383106111e857505050505f5b8151811015610e5357835f526011602052610dab60208060405f20610d8d85876137cf565b5190604051938285935191829101845e8201908152030190206128ae565b8051610dbb575b50600101610d68565b610e4c6002600b84966010602080968180610dd860019b8d6137cf565b516040519a878c985191829101848a015e8701906f163d913a3930b4ba2fba3cb832911d1160811b83830152805192839101603083015e0101906a1116113b30b63ab2911d1160a91b84830152805192839101601b83015e010161227d60f01b838201520301601d19810184520182612754565b9290610db2565b505090610e9260405191610e8d600160208581808201988051918291018a5e8101605d60f81b838201520301601e19810186520184612754565b61334b565b90604051938492683d913730b6b2911d1160b91b60208501525f90600454610eb98161271c565b90600181169081156111ca5750600114611181575b5061202360f01b8252805191908290602001600283015e61088b60f21b600292909101918201526e113232b9b1b934b83a34b7b7111d1160891b60048201526006545f9291610f1c8261271c565b916001811690811561115c57506001146110ff575b5050610fac94600f93602060019694600b9461088b60f21b8252681134b6b0b3b2911d1160b91b60028301528051928391018683015e019061088b60f21b848301526c1130ba3a3934b13aba32b9911d60991b600d830152518092601a83015e0101607d60f81b838201520301601e19810184520182612754565b806060918151908161100f575b6103c360206103af603d876040519384917f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000828401528051918291018484015e81015f838201520301601f198101835282612754565b909192506003600283010460021b906040517f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f5260208101928082019260208681860198010194600460038751935f89525b0191603f8351818160121c16515f538181600c1c1651600153818160061c165160025316516003535f5181520190888210156110cc5760049060039061108b565b506103c397506020966040603d965f946103af9952016040526003613d3d60f01b91066002048203525281529350610fb9565b60065f90815292935090917ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f5b838210611142575050016013019084600f610f31565b80546013838501015288965060209091019060010161112c565b60ff19166013838101919091528315159093029091019091019250859050600f610f31565b60045f908152919250905f805160206138048339815191525b8282106111b05750508401602901906020610ece565b80546029838b01015288965060209091019060010161119a565b60209450602992915060ff1916828801528015150286010191610ece565b6001602081926111f7856128ae565b815201920192019190610d5b565b63d03ce9df60e01b5f5260045ffd5b34610371575f36600319011261037157602060105460a01c604051908152f35b34610371576060366003190112610371576004356001600160401b038111610371576112649036906004016129eb565b906024356001600160401b038111610371576112849036906004016129eb565b6044939193356001600160401b038111610371576112a69036906004016129eb565b9290936112b1613207565b6001600160401b038211610891576112ca60045461271c565b601f811161158f575b505f90601f831160011461151d5761130292915f9183611512575b50508160011b915f199060031b1c19161790565b6004555b6001600160401b0381116108915761131f60055461271c565b601f81116114e1575b505f601f821160011461147d5781906113579394955f926114725750508160011b915f199060031b1c19161790565b6005555b6001600160401b0381116108915761137460065461271c565b601f8111611419575b505f601f82116001146113ba5781906113aa935f926113af5750508160011b915f199060031b1c19161790565b600655005b0135905083806112ee565b601f1982169260065f5260205f20915f5b858110611401575083600195106113e8575b505050811b01600655005b01355f19600384901b60f8161c191690558280806113dd565b909260206001819286860135815501940191016113cb565b60065f52611462907ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f601f840160051c81019160208510611468575b601f0160051c0190612e5c565b8261137d565b9091508190611455565b0135905085806112ee565b601f1982169460055f5260205f20915f5b8781106114c95750836001959697106114b0575b505050811b0160055561135b565b01355f19600384901b60f8161c191690558480806114a2565b9092602060018192868601358155019401910161148e565b61150c9060055f5260205f20601f840160051c8101916020851061146857601f0160051c0190612e5c565b84611328565b0135905087806112ee565b60045f9081525f805160206138048339815191529290601f198516905b818110611577575090846001959493921061155e575b505050811b01600455611306565b01355f19600384901b60f8161c19169055868080611550565b9193602060018192878701358155019501920161153a565b60045f526115c4905f80516020613804833981519152601f850160051c8101916020861061146857601f0160051c0190612e5c565b866112d3565b34610371575f36600319011261037157602060ff600b5416604051908152f35b6080366003190112610371576115fe6126b6565b6116066126cc565b906044356064356001600160401b038111610371576116299036906004016129eb565b611637838686979497612ad4565b813b61163f57005b6104859461164e913691612a78565b926132b9565b34610371575f366003190112610371576020600a54604051908152f35b346103715761167f3661295d565b151581601c52670a5a2e7a00000000600852335f52806030600c20555f5260018060a01b0316337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa3005b34610371575f366003190112610371576010546040516001600160a01b039091168152602090f35b34610371576020366003190112610371576004355f52601260205260405f20805461171f81612e08565b9161172d6040519384612754565b81835260208301905f5260205f205f915b83831061175357604051806103c3878261298c565b600160208192611762856128ae565b81520192019201919061173e565b34610371575f366003190112610371576103c36103af612819565b34610371576040366003190112610371576117a46126b6565b602435906bffffffffffffffffffffffff821691828103610371576117c7613207565b6103e883116118235760a01b6001600160a01b0319166001600160a01b039091169081176010556040805191825260208201929092527f8039bd6e4e7dba001c8840eb2e118d9d131246faa7d0d04335f7305127ec0b109190a1005b63e0e54ced60e01b5f5260045ffd5b34610371575f36600319011261037157638b78c6d819546040516001600160a01b039091168152602090f35b34610371575f366003190112610371576002546040516001600160a01b039091168152602090f35b34610371576020366003190112610371576004356118a2613207565b7f585c2700029358052c68e4d3f003a64ac491d362f58e2f3d66d6e4bb21ca8bc160406003548151908152836020820152a1600355005b34610371576040366003190112610371576024356001600160401b0381116103715761190c6104859136906004016129eb565b90611915613207565b6004355f52600f60205260405f20612e72565b3461037157602036600319011261037157600435611944613207565b7ffd69edeceaf1d6832d935be1fba54ca93bf17e71520c6c9ffc08d6e9529f87576040600c548151908152836020820152a1600c55005b5f3660031901126103715761198e613207565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f638b78c6d81955005b34610371576020366003190112610371576119dd6126b6565b8015611a0a57673ec412a9852d173d60c11b601c525f52602063ffffffff601c600c205416604051908152f35b638f4eb6045f526004601cfd5b34610371576020366003190112610371576004355f52600f6020526103c36103af60405f206128ae565b34610371575f36600319011261037157611a59613207565b600180546001600160a01b03191690557feaf2b442cd5e40fc7c4d20092b3f0d1bc2ea72bf451aa225a217a9719eed3fe95f80a1005b346103715760203660031901126103715760043560135481101561037157601354811015611ad65760135f525f805160206137e4833981519152016103af6103c3916128ae565b634e487b7160e01b5f52603260045260245ffd5b34610371576020366003190112610371576020611b0d611b086126b6565b613050565b604051908152f35b34610371576020366003190112610371576004355f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b03168015611b5e57602090604051908152f35b63ceea21b65f526004601cfd5b34610371575f366003190112610371575f546040516001600160a01b039091168152602090f35b3461037157604036600319011261037157611bab6126b6565b6024356001600160401b038111610371576020916109e3611bd3611c01933690600401612a18565b919092604051868101916bffffffffffffffffffffffff199060601b168252601481526109d4603482612754565b6040519015158152f35b34610371576040366003190112610371576004356001600160401b03811161037157611c3b903690600401612a18565b906024356001600160401b03811161037157611c5b903690600401612a18565b9260018060a01b03638b78c6d819541633148015611d01575b611c7d90612e1f565b838103611cc3575f5b818110611c8f57005b80611cbd611ca06001938887612fb3565b90611cac84878a612ff4565b355f52600f60205260405f20612e72565b01611c86565b60405162461bcd60e51b8152602060048201526016602482015275082e4e4c2f2e640d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606490fd5b506001546001600160a01b03163314611c74565b3461037157602036600319011261037157611d2e6126b6565b611d36613207565b6002546001600160a01b0391821691829082167f10e9b6d73105db46c6a41a698f35efb8e1688178fe274b7b21f0bdc792de3ea55f80a36001600160a01b03191617600255005b34610371576060366003190112610371576004356024356001600160401b03811161037157611db09036906004016129eb565b906044356001600160401b03811161037157611dd09036906004016129eb565b929092335f52601460205260ff60405f2054168015611f24575b611df390612e1f565b5f858152673ec412a9852d173d60c11b601c5260209020850185015460601b15611eec577f34aa5916666fc84b1baeab0860d749d91bdfddb0a676056eed0841ead2ebdad393611ec391865f526011602052611e6760405f2060206040518092888a8337888201908152030190205461271c565b1580611ee3575b611ec8575b865f526011602052611e9e818360405f20602060405180928a8c83378a820190815203019020612e72565b611eb5604051958695604087526040870191612f93565b918483036020860152612f93565b0390a2005b865f526012602052611ede848660405f20612f63565b611e73565b50801515611e6e565b60405162461bcd60e51b815260206004820152601060248201526f151bdad95b881b9bdd081b5a5b9d195960821b6044820152606490fd5b50638b78c6d819546001600160a01b03163314611dea565b5f3660031901126103715763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b34610371575f36600319011261037157602060405160fa8152f35b34610371575f36600319011261037157601354611fb781612e08565b90611fc56040519283612754565b8082526020820160135f525f805160206137e48339815191525f915b838310611ff657604051806103c3878261298c565b600160208192612005856128ae565b815201920192019190611fe1565b34610371576020366003190112610371576004355f818152673ec412a9852d173d60c11b601c5260209020810181015460601b15611205575f61206061205b61208a9361334b565b612d72565b60018060a01b036002541660035460405180958194829363126187bf60e01b845260048401612df1565b03915afa8015612105575f906120b3575b6103c390604051918291602083526020830190612692565b503d805f833e6120c38183612754565b810190602081830312610371578051906001600160401b038211610371570181601f82011215610371576103c39181602061210093519101612dbb565b61209b565b6040513d5f823e3d90fd5b34610371576040366003190112610371576121296126b6565b602435612134613207565b61214081600754612bf2565b60085410610a5f575f5b81811061215357005b60019061216e612164600754612bff565b8060075585613223565b0161214a565b34610371575f366003190112610371576020600d54604051908152f35b346103715760207f45ae6530c572ff9dace11cb11f624684bc14b6d5dd029a468ae53a464590950a6121c23661295d565b92906121cc613207565b60018060a01b031692835f526014825260405f209015159060ff1981541660ff8316179055604051908152a2005b612203366126e2565b6122108183859495612ad4565b823b61221857005b610485926040519261222b602085612754565b5f84526132b9565b34610371575f3660031901126103715760206040516103e88152f35b34610371575f36600319011261037157612267613207565b3068929eee149b4bd21268541461229a573068929eee149b4bd212685561228c612c49565b3868929eee149b4bd2126855005b63ab143c065f526004601cfd5b34610371576020366003190112610371576001600160a01b036122c86126b6565b165f52600e602052602060405f2054604051908152f35b34610371575f366003190112610371576020600c54604051908152f35b34610371575f366003190112610371576020600354604051908152f35b602036600319011261037157600435600260ff600b5416036123b45761234181600754612bf2565b60085410610a5f5761235581600a54612bcb565b3410610a5057335f52600e6020526123718160405f2054612bf2565b600d5410610a4157335f52600e60205260405f20612390828254612bf2565b90555f5b81811061239d57005b6001906123ae610a22600754612bff565b01612394565b63cd967e3560e01b5f5260045ffd5b346103715760406123d33661267c565b90506127106123e9601054928360a01c90612bcb565b83516001600160a01b039093168352046020820152f35b5f3660031901126103715763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b34610371576020366003190112610371576001600160a01b0361246a6126b6565b165f526014602052602060ff60405f2054166040519015158152f35b610485612492366126e2565b91612ad4565b34610371575f366003190112610371576020600754604051908152f35b6040366003190112610371576124c96126b6565b6024355f818152673ec412a9852d173d60c11b3317601c526020902081018101805491926001600160a01b039081169216908115611b5e57829082331433151715612539575b600101557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b9050815f526030600c20541561255057829061250f565b634b6e7f185f526004601cfd5b34610371576020366003190112610371576004355f818152673ec412a9852d173d60c11b601c5260209020810101805460601b15611b5e57600101546040516001600160a01b039091168152602090f35b34610371577f6546f60f34df611fa42503098acc39d5ab88bc73febe64b3cc14e5a92e3a66a760406125df3661267c565b6125e7613207565b8160095580600a5582519182526020820152a1005b34610371575f366003190112610371576020611b0d612aae565b34610371576020366003190112610371576004356001600160e01b0319811691908281036103715760209263152a902d60e11b14908115612659575b5015158152f35b905060e01c635b5e139f8114906301ffc9a76380ac58cd82149114171783612652565b6040906003190112610371576004359060243590565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361037157565b602435906001600160a01b038216820361037157565b6060906003190112610371576004356001600160a01b038116810361037157906024356001600160a01b0381168103610371579060443590565b90600182811c9216801561274a575b602083101461273657565b634e487b7160e01b5f52602260045260245ffd5b91607f169161272b565b90601f801991011681019081106001600160401b0382111761089157604052565b604051905f82600454916127888361271c565b80835292600181169081156127fa57506001146127ae575b6127ac92500383612754565b565b5060045f90815290915f805160206138048339815191525b8183106127de5750509060206127ac928201016127a0565b60209193508060019154838589010152019101909184926127c6565b602092506127ac94915060ff191682840152151560051b8201016127a0565b604051905f826005549161282c8361271c565b80835292600181169081156127fa575060011461284f576127ac92500383612754565b5060055f90815290917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b8183106128925750509060206127ac928201016127a0565b602091935080600191548385890101520191019091849261287a565b9060405191825f8254926128c18461271c565b808452936001811690811561292a57506001146128e6575b506127ac92500383612754565b90505f9291925260205f20905f915b81831061290e5750509060206127ac928201015f6128d9565b60209193508060019154838589010152019101909184926128f5565b9050602092506127ac94915060ff191682840152151560051b8201015f6128d9565b9061087e5761295a906128ae565b90565b6040906003190112610371576004356001600160a01b0381168103610371579060243580151581036103715790565b602081016020825282518091526040820191602060408360051b8301019401925f915b8383106129be57505050505090565b90919293946020806129dc600193603f198682030187528951612692565b970193019301919392906129af565b9181601f84011215610371578235916001600160401b038311610371576020838186019501011161037157565b9181601f84011215610371578235916001600160401b038311610371576020808501948460051b01011161037157565b8054821015611ad6575f5260205f2001905f90565b6001600160401b03811161089157601f01601f191660200190565b929192612a8482612a5d565b91612a926040519384612754565b829481845281830111610371578281602093845f960137010152565b60ff600b541660018114612acd57600214612ac7575f90565b600a5490565b5060095490565b5f838152673ec412a9852d173d60c11b3317601c52602090208301830180546001600160a01b0393841693928316928116808414810215612bb65750825f528160010180548033148533141715612b9f575b612b96575b50838318189055601c600c205f198154019055815f52601c600c2060018154019063ffffffff8216840215612b8157557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4565b67ea553b3401336cea841560021b526004601cfd5b5f90555f612b2b565b6030600c2054612b2657634b6e7f185f526004601cfd5b67ceea21b6a1148100901560021b526004601cfd5b81810292918115918404141715612bde57565b634e487b7160e01b5f52601160045260245ffd5b91908201809211612bde57565b5f198114612bde5760010190565b91908203918211612bde57565b3d15612c44573d90612c2b82612a5d565b91612c396040519384612754565b82523d5f602084013e565b606090565b478015612d6f5760fa810281810460fa03612bde57612710612c6d91048092612c0d565b5f8080808560018060a01b038254165af1612c86612c1a565b5015612d2a575f80808084638b78c6d819545af1612ca2612c1a565b5015612ced57638b78c6d819546040805192835260208301939093526001600160a01b0316917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc691a2565b60405162461bcd60e51b815260206004820152601560248201527413dddb995c881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f5472656173757279207472616e73666572206661696c656400000000000000006044820152606490fd5b50565b906127ac60046028602094604051958691672f696d616765732f60c01b828401528051918291018484015e8101632e706e6760e01b838201520301601b19810185520183612754565b929192612dc782612a5d565b91612dd56040519384612754565b829481845281830111610371578281602093845f96015e010152565b60409061295a939281528160208201520190612692565b6001600160401b0381116108915760051b60200190565b15612e2657565b60405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606490fd5b818110612e67575050565b5f8155600101612e5c565b9092916001600160401b03811161089157612e8d825461271c565b601f8111612f33575b505f601f8211600114612ed4578190612ec59394955f92612ec95750508160011b915f199060031b1c19161790565b9055565b013590505f806112ee565b601f19821694835f5260205f20915f5b878110612f1b575083600195969710612f02575b505050811b019055565b01355f19600384901b60f8161c191690555f8080612ef8565b90926020600181928686013581550194019101612ee4565b612f5d90835f5260205f20601f840160051c8101916020851061146857601f0160051c0190612e5c565b5f612e96565b9190918054600160401b81101561089157612f8391600182018155612a48565b92909261087e576127ac92612e72565b908060209392818452848401375f828201840152601f01601f1916010190565b9190811015611ad65760051b81013590601e19813603018212156103715701908135916001600160401b038311610371576020018236038113610371579190565b9190811015611ad65760051b0190565b92919061301081612e08565b9361301e6040519586612754565b602085838152019160051b810192831161037157905b82821061304057505050565b8135815260209182019101613034565b6001600160a01b03165f818152600e6020526040902054600d54908111156130a857613088915f52600e60205260405f205490612c0d565b61309760085460075490612c0d565b808210156130a3575090565b905090565b50505f90565b156130b557565b60405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606490fd5b9081606091031261037157805180151581036103715791602082015163ffffffff811681036103715760409092015160ff811681036103715790565b90815f52600f60205261313d60405f206128ae565b80516131d15750606061315561205b61317f9461334b565b60018060a01b036002541660035460405180968194829363840ce67d60e01b845260048401612df1565b03915afa908115612105575f80935f9361319a575b50929190565b919350506131c0915060603d6060116131ca575b6131b88183612754565b8101906130ec565b929092915f613194565b503d6131ae565b60025460035460405163840ce67d60e01b8152945060609285926001600160a01b0316918391829161317f919060048401612df1565b638b78c6d81954330361321657565b6382b429005f526004601cfd5b60018060a01b0316815f52673ec412a9852d173d60c11b601c5260205f208201820180548060601b6132ac5782179055805f52601c600c2060018154019063ffffffff821683021561329757555f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4565b67ea553b3401336cea831560021b526004601cfd5b63c991cbb15f526004601cfd5b9060a46020939460405195869463150b7a028652338787015260018060a01b03166040860152606085015260808085015280518091818060a0880152613337575b505001905f601c8401915af115613329575b5163757a42ff60e11b0161331c57565b63d1a57ed65f526004601cfd5b3d1561330c573d5f823e3d90fd5b818760c08801920160045afa50805f6132fa565b90604051600a608082019360a083016040525f8552935b5f19019360308282060185530492831561337e57600a90613362565b809350608091030191601f1901918252565b9091815191826133a2575b5090501490565b8060208092019360051b0101905b8251811160051b90815260208351911852602060405f209201918183106133b057915050805f61339b565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3638b78c6d81955565b602081830312610371578051906001600160401b03821161037157019080601f8301121561037157815161295a92602001612dbb565b906005811015611ad65760051b0190565b606090805f52600f60205261347660405f206128ae565b91825161373a575b506134889061334b565b906040519160a083018381106001600160401b03821117610891576040526134af81612d72565b8352604051672f696d616765732f60c01b60208201528151906134f96004602883602087019580878484015e8101632e6a706760e01b838201520301601b19810184520182612754565b6020850152604051672f696d616765732f60c01b60208201526135406004602883865180878484015e8101632e73766760e01b838201520301601b19810184520182612754565b6040850152604051602f60f81b60208201526135806004602183865180878484015e8101632e706e6760e01b838201520301601b19810184520182612754565b60608501526135c1600460216040518094602f60f81b6020830152865180918484015e8101632e6a706760e01b838201520301601b19810184520182612754565b608084015260025460035493906001600160a01b03165f5b6005811061366d57505050916039602061360384829661295a965115155f1461365d57509361334b565b926040519586947f68747470733a2f2f6d65676177617272656e2e78797a2f632f00000000000000828701528051918291018587015e8401908382015f8152815193849201905e01015f815203601f198101835282612754565b6136679150612d72565b9361334b565b613698606061367c838661344e565b516040518093819263840ce67d60e01b83528b60048401612df1565b0381865afa908115612105575f9161371a575b506136b8576001016135d9565b5f94506136e99593506136cb919261344e565b51604051627b457760e71b8152948593849283929160048401612df1565b03915afa908115612105575f916136fe575090565b61295a91503d805f833e6137128183612754565b810190613418565b613732915060603d81116131ca576131b88183612754565b50505f6136ab565b60025460035460405163840ce67d60e01b81526001600160a01b0390921692909181818061376c898760048401612df1565b0381875afa918215612105575f926137b0575b505061378b575061347e565b604051627b457760e71b8152935f9350849291839182916136e9919060048401612df1565b6137c69250803d106131ca576131b88183612754565b50505f8061377f565b8051821015611ad65760209160051b01019056fe66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0908a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19ba2646970667358221220a2d8355f899f5b9751928a68615a74022ac9c62202eba6dfd3f4feb83014385964736f6c634300081a0033"
}

path: package.json
content: {
  "name": "warren-nft-clawhub-upload",
  "version": "1.0.0",
  "description": "",
  "main": "deploy-nft.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs",
  "dependencies": {
    "ethers": "^6.16.0"
  }
}


path: deploy-nft.js
content: #!/usr/bin/env node

/**
 * Warren NFT Collection Deploy - Self-contained on-chain NFT deployment
 *
 * Deploys NFT collections permanently on MegaETH blockchain.
 * Images stored on-chain via SSTORE2 fractal tree in WarrenContainer.
 *
 * Setup:  bash setup.sh
 * Usage:  PRIVATE_KEY=0x... node deploy-nft.js --images-folder ./art/ --name "My NFT" --symbol "MNFT"
 *         PRIVATE_KEY=0x... node deploy-nft.js --generate-svg 10 --name "Gen Art" --symbol "GART"
 */

const { ethers } = require('ethers');
const fs = require('fs');
const path = require('path');

// ============================================================================
// Configuration
// ============================================================================

const RPC_URL = process.env.RPC_URL || 'https://mainnet.megaeth.com/rpc';
const CHAIN_ID = parseInt(process.env.CHAIN_ID || '4326');
const GENESIS_KEY_ADDRESS = process.env.GENESIS_KEY_ADDRESS || [REDACTED_SECRET];
const RABBIT_AGENT_ADDRESS = process.env.RABBIT_AGENT_ADDRESS || [REDACTED_SECRET];
const CONTAINER_ADDRESS = process.env.CONTAINER_ADDRESS || [REDACTED_SECRET];
const RENDERER_ADDRESS = process.env.RENDERER_ADDRESS || [REDACTED_SECRET];
const TREASURY_ADDRESS = process.env.TREASURY_ADDRESS || '0xcea9d92ddb052e914ab665c6aaf1ff598d18c550';
const REGISTER_API = process.env.REGISTER_API || 'https://thewarren.app/api/container-nfts';
const CHUNK_SIZE = parseInt(process.env.CHUNK_SIZE || '15000');
const GROUP_SIZE = parseInt(process.env.GROUP_SIZE || '500');
const BATCH_SIZE = 5;
const RETRY_MAX = 3;
const RETRY_DELAY = 2000;

// ============================================================================
// MegaETH Multidimensional Gas Model (ported from Warren's megaeth-gas.ts)
// ============================================================================

const MEGAETH_GAS = {
  INTRINSIC_COMPUTE: 21_000n,
  INTRINSIC_STORAGE: 39_000n,
  CONTRACT_CREATION_COMPUTE: 32_000n,
  CODE_DEPOSIT_PER_BYTE: 10_000n,
  CALLDATA_ZERO_PER_BYTE: 40n,
  CALLDATA_NONZERO_PER_BYTE: 160n,
  EIP7623_FLOOR_ZERO_PER_BYTE: 100n,
  EIP7623_FLOOR_NONZERO_PER_BYTE: 400n,
  SSTORE2_COMPUTE_ESTIMATE: 700_000n,
  PAGE_BYTECODE_OVERHEAD: 100n,
};
const MAX_GAS_PER_TX = 200_000_000n;

function estimateChunkGasLimit(chunkSizeBytes) {
  const dataSize = BigInt(chunkSizeBytes) + MEGAETH_GAS.PAGE_BYTECODE_OVERHEAD;
  const computeGas = MEGAETH_GAS.INTRINSIC_COMPUTE + MEGAETH_GAS.CONTRACT_CREATION_COMPUTE + MEGAETH_GAS.SSTORE2_COMPUTE_ESTIMATE;
  const codeDeposit = dataSize * MEGAETH_GAS.CODE_DEPOSIT_PER_BYTE;
  const nonZeroBytes = BigInt(Math.floor(chunkSizeBytes * 0.8));
  const zeroBytes = BigInt(chunkSizeBytes) - nonZeroBytes;
  const calldataRegular = zeroBytes * MEGAETH_GAS.CALLDATA_ZERO_PER_BYTE + nonZeroBytes * MEGAETH_GAS.CALLDATA_NONZERO_PER_BYTE;
  const calldataFloor = zeroBytes * MEGAETH_GAS.EIP7623_FLOOR_ZERO_PER_BYTE + nonZeroBytes * MEGAETH_GAS.EIP7623_FLOOR_NONZERO_PER_BYTE;
  const calldata = calldataRegular > calldataFloor ? calldataRegular : calldataFloor;
  const storageGas = MEGAETH_GAS.INTRINSIC_STORAGE + codeDeposit + calldata;
  const total = computeGas + storageGas;
  const withBuffer = (total * 150n) / 100n;
  const MIN_GAS = 10_000_000n;
  const gasLimit = withBuffer < MIN_GAS ? MIN_GAS : withBuffer;
  return gasLimit < MAX_GAS_PER_TX ? gasLimit : MAX_GAS_PER_TX;
}

// ============================================================================
// ABIs & Bytecode
// ============================================================================

// Page.sol compiled bytecode — see page_bytecode.js for source & verification info
const PAGE_BYTECODE = require('./page_bytecode.js');
const PAGE_ABI = [{"type":"constructor","inputs":[{"name":"_content","type":"bytes"}],"stateMutability":"nonpayable"}];

// WarrenLaunchedNFT compiled bytecode — loaded from companion JSON file
const NFT_BYTECODE = JSON.parse(fs.readFileSync(path.join(__dirname, 'WarrenLaunchedNFT.bytecode.json'), 'utf8')).bytecode;
const NFT_ABI = [{"type":"constructor","inputs":[{"name":"_renderer","type":"address"},{"name":"_containerId","type":"uint256"},{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_description","type":"string"},{"name":"_maxSupply","type":"uint256"},{"name":"_whitelistPrice","type":"uint256"},{"name":"_publicPrice","type":"uint256"},{"name":"_maxPerWallet","type":"uint256"},{"name":"_merkleRoot","type":"bytes32"},{"name":"_royaltyReceiver","type":"address"},{"name":"_royaltyBps","type":"uint96"},{"name":"_treasury","type":"address"},{"name":"_owner","type":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"setMintState","inputs":[{"name":"_state","type":"uint8"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"tokenURI","inputs":[{"name":"tokenId","type":"uint256"}],"outputs":[{"name":"","type":"string"}],"stateMutability":"view"},{"type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}],"stateMutability":"view"},{"type":"function","name":"maxSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}],"stateMutability":"view"},{"type":"function","name":"mintState","inputs":[],"outputs":[{"name":"","type":"uint8"}],"stateMutability":"view"}];

const CONTAINER_ABI = [{"type":"function","name":"mintSite","inputs":[{"name":"to","type":"address"},{"name":"siteType","type":"uint8"},{"name":"inputFiles","type":"tuple[]","components":[{"name":"path","type":"string"},{"name":"chunk","type":"address"},{"name":"size","type":"uint32"},{"name":"depth","type":"uint8"}]}],"outputs":[{"name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"getFileByPath","inputs":[{"name":"tokenId","type":"uint256"},{"name":"path","type":"string"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"chunk","type":"address"},{"name":"size","type":"uint32"},{"name":"depth","type":"uint8"}]}],"stateMutability":"view"}];

const GENESIS_KEY_ABI = ['function mint() external payable', 'function balanceOf(address) view returns (uint256)'];
const RABBIT_AGENT_ABI = ['function mint() external', 'function balanceOf(address) view returns (uint256)'];

// ============================================================================
// Helpers
// ============================================================================

const sleep = (ms) => new Promise(r => setTimeout(r, ms));

function isRetryable(e) {
  const msg = (e.message || '').toLowerCase();
  return msg.includes('rate') || msg.includes('429') || msg.includes('timeout') || msg.includes('nonce') || e.code === -32022;
}

async function withRetry(fn, label) {
  for (let i = 1; i <= RETRY_MAX; i++) {
    try { return await fn(); } catch (e) {
      if (isRetryable(e) && i < RETRY_MAX) {
        console.log(`  ⚠ ${label} attempt ${i} failed, retrying...`);
        await sleep(RETRY_DELAY * i);
      } else throw e;
    }
  }
}

// ============================================================================
// Genesis Key NFT
// ============================================================================

async function ensureGenesisKey(wallet) {
  const humanNft = new ethers.Contract(GENESIS_KEY_ADDRESS, GENESIS_KEY_ABI, wallet);
  if (Number(await humanNft.balanceOf(wallet.address)) > 0) {
    console.log('🔑 Genesis Key (Human): ✅');
    return;
  }

  if (!RABBIT_AGENT_ADDRESS || RABBIT_AGENT_ADDRESS === ethers.ZeroAddress) {
    throw new Error('No Genesis Key found and RABBIT_AGENT_ADDRESS is not configured.');
  }

  const botNft = new ethers.Contract(RABBIT_AGENT_ADDRESS, RABBIT_AGENT_ABI, wallet);
  if (Number(await botNft.balanceOf(wallet.address)) > 0) {
    console.log('🤖 0xRabbit.agent Key: ✅');
    return;
  }

  console.log('🤖 Minting 0xRabbit.agent Key (free)...');
  const tx = await botNft.mint({ gasLimit: 500000n });
  await tx.wait();
  console.log('  ✅ 0xRabbit.agent Key minted!');
}

// ============================================================================
// Page Deployment (SSTORE2)
// ============================================================================

async function deployPage(wallet, provider, content, nonce, label) {
  return withRetry(async () => {
    const factory = new ethers.ContractFactory(PAGE_ABI, PAGE_BYTECODE, wallet);
    const deployTx = await factory.getDeployTransaction(content);
    const contentSize = Buffer.isBuffer(content) ? content.length : Buffer.from(content).length;
    deployTx.gasLimit = estimateChunkGasLimit(contentSize);
    if (nonce !== undefined) deployTx.nonce = nonce;
    const tx = await wallet.sendTransaction(deployTx);
    const receipt = await tx.wait();
    const code = await provider.getCode(receipt.contractAddress);
    if (!code || code.length <= 2) throw new Error(`${label}: verification failed`);
    return receipt;
  }, label);
}

// ============================================================================
// Fractal Tree
// ============================================================================

function chunkBuffer(buf, size) {
  const chunks = [];
  for (let i = 0; i < buf.length; i += size) chunks.push(buf.subarray(i, Math.min(i + size, buf.length)));
  return chunks;
}

async function deployChunks(wallet, provider, chunks, prefix = '') {
  const addrs = [];
  for (let bs = 0; bs < chunks.length; bs += BATCH_SIZE) {
    const be = Math.min(bs + BATCH_SIZE, chunks.length);
    const batch = chunks.slice(bs, be);
    const baseNonce = await provider.getTransactionCount(wallet.address, 'latest');
    const results = await Promise.all(batch.map(async (chunk, idx) => {
      await sleep(idx * 50);
      const receipt = await deployPage(wallet, provider, chunk, baseNonce + idx, `${prefix}Chunk ${bs + idx + 1}/${chunks.length}`);
      return { receipt, idx: bs + idx };
    }));
    for (const { receipt, idx } of results.sort((a, b) => a.idx - b.idx)) {
      addrs.push(receipt.contractAddress);
    }
    if (be < chunks.length) await sleep(300);
  }
  return addrs;
}

async function buildTree(wallet, provider, addresses) {
  let level = [...addresses];
  let depth = 0;
  while (level.length > 1) {
    depth++;
    const parent = [];
    const groups = Math.ceil(level.length / GROUP_SIZE);
    const baseNonce = await provider.getTransactionCount(wallet.address, 'latest');
    for (let i = 0; i < level.length; i += GROUP_SIZE) {
      const group = level.slice(i, i + GROUP_SIZE);
      const concat = Buffer.concat(group.map(a => Buffer.from(ethers.getBytes(a))));
      const ni = Math.floor(i / GROUP_SIZE);
      await sleep(ni * 50);
      const receipt = await deployPage(wallet, provider, concat, baseNonce + ni, `Node D${depth}-${ni + 1}/${groups}`);
      parent.push(receipt.contractAddress);
    }
    level = parent;
  }
  return { rootChunk: level[0], depth };
}

async function deployImageData(wallet, provider, imageBuffer, label) {
  const chunks = chunkBuffer(imageBuffer, CHUNK_SIZE);
  console.log(`    ${label}: ${imageBuffer.length} bytes, ${chunks.length} chunk(s)`);
  const addrs = await deployChunks(wallet, provider, chunks, `${label} `);
  if (addrs.length === 1) return { rootChunk: addrs[0], depth: 0, totalSize: imageBuffer.length };
  const { rootChunk, depth } = await buildTree(wallet, provider, addrs);
  return { rootChunk, depth, totalSize: imageBuffer.length };
}

// ============================================================================
// Image Discovery
// ============================================================================

function discoverImages(folderPath) {
  if (!fs.existsSync(folderPath)) throw new Error(`Folder not found: ${folderPath}`);
  const files = fs.readdirSync(folderPath)
    .filter(f => /\.(png|jpg|jpeg|svg|gif|webp)$/i.test(f))
    .sort((a, b) => {
      const na = parseInt(a) || 0, nb = parseInt(b) || 0;
      return na !== nb ? na - nb : a.localeCompare(b);
    });
  if (files.length === 0) throw new Error(`No image files found in ${folderPath}`);
  if (files.length > 256) throw new Error(`Too many images (${files.length}). Max 256 per container.`);
  return files.map((f, i) => {
    const ext = path.extname(f).toLowerCase();
    return {
      originalPath: path.join(folderPath, f),
      containerPath: `/images/${i + 1}${ext}`,
      buffer: fs.readFileSync(path.join(folderPath, f)),
    };
  });
}

// ============================================================================
// SVG Generator
// ============================================================================

function generateSVGs(count) {
  const palettes = [
    ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'],
    ['#E74C3C', '#8E44AD', '#3498DB', '#1ABC9C', '#F39C12'],
    ['#6C5CE7', '#FD79A8', '#FDCB6E', '#00B894', '#0984E3'],
    ['#2D3436', '#DFE6E9', '#74B9FF', '#A29BFE', '#FD79A8'],
    ['#FAB1A0', '#81ECEC', '#74B9FF', '#A29BFE', '#FFEAA7'],
    ['#FF9FF3', '#F368E0', '#FF6348', '#FFA502', '#2ED573'],
    ['#00D2D3', '#54A0FF', '#5F27CD', '#01A3A4', '#EE5A24'],
    ['#BADC58', '#F9CA24', '#F0932B', '#EB4D4B', '#6AB04C'],
  ];

  const shapes = ['circle', 'rect', 'polygon', 'ellipse'];
  const images = [];

  for (let i = 0; i < count; i++) {
    const seed = i * 7919 + 31;
    const palette = palettes[seed % palettes.length];
    const bg = palette[(seed * 3) % palette.length];
    let svgContent = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">`;
    svgContent += `<rect width="400" height="400" fill="${bg}" opacity="0.3"/>`;

    const numShapes = 5 + (seed % 8);
    for (let s = 0; s < numShapes; s++) {
      const color = palette[(seed + s * 13) % palette.length];
      const opacity = 0.3 + ((seed + s * 7) % 7) / 10;
      const shape = shapes[(seed + s) % shapes.length];
      const cx = (seed * (s + 1) * 17) % 400;
      const cy = (seed * (s + 1) * 23) % 400;
      const r = 20 + (seed * (s + 1) * 11) % 80;

      if (shape === 'circle') {
        svgContent += `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${color}" opacity="${opacity.toFixed(1)}"/>`;
      } else if (shape === 'rect') {
        svgContent += `<rect x="${cx - r / 2}" y="${cy - r / 2}" width="${r}" height="${r}" rx="${r / 5}" fill="${color}" opacity="${opacity.toFixed(1)}"/>`;
      } else if (shape === 'polygon') {
        const points = [];
        for (let p = 0; p < 3 + (seed + s) % 4; p++) {
          const angle = (p * 2 * Math.PI) / (3 + (seed + s) % 4);
          points.push(`${cx + r * Math.cos(angle)},${cy + r * Math.sin(angle)}`);
        }
        svgContent += `<polygon points="${points.join(' ')}" fill="${color}" opacity="${opacity.toFixed(1)}"/>`;
      } else {
        svgContent += `<ellipse cx="${cx}" cy="${cy}" rx="${r}" ry="${r * 0.6}" fill="${color}" opacity="${opacity.toFixed(1)}"/>`;
      }
    }

    svgContent += `<text x="200" y="380" font-family="monospace" font-size="16" fill="white" text-anchor="middle" opacity="0.8">#${i + 1}</text>`;
    svgContent += `</svg>`;

    images.push({
      originalPath: `generated_${i + 1}.svg`,
      containerPath: `/images/${i + 1}.svg`,
      buffer: Buffer.from(svgContent, 'utf8'),
    });
  }

  return images;
}

// ============================================================================
// Container Minting
// ============================================================================

async function mintContainer(wallet, deployedImages) {
  console.log('\n📦 Phase 2: Minting NFT Container...');
  const container = new ethers.Contract(CONTAINER_ADDRESS, CONTAINER_ABI, wallet);

  const fileInputs = deployedImages.map(img => ({
    path: img.containerPath,
    chunk: img.rootChunk,
    size: img.totalSize,
    depth: img.depth,
  }));

  const tx = await container.mintSite(wallet.address, 2, fileInputs, { gasLimit: 100_000_000n });
  const receipt = await tx.wait();

  const transferTopic = ethers.id('Transfer(address,address,uint256)');
  const log = receipt.logs.find(l => l.topics?.[0] === transferTopic);
  const containerId = log?.topics?.[3] ? Number(BigInt(log.topics[3])) : null;

  console.log(`  ✅ Container ID: ${containerId}, Gas: ${receipt.gasUsed}`);
  return containerId;
}

// ============================================================================
// NFT Collection Deployment
// ============================================================================

async function deployCollection(wallet, provider, containerId, config) {
  console.log('\n🎨 Phase 3: Deploying NFT Collection...');

  const factory = new ethers.ContractFactory(NFT_ABI, NFT_BYTECODE, wallet);
  const deployTx = await factory.getDeployTransaction(
    RENDERER_ADDRESS,
    containerId,
    config.name,
    config.symbol,
    config.description,
    config.maxSupply,
    ethers.parseEther(config.whitelistPrice || '0'),
    ethers.parseEther(config.publicPrice || '0'),
    config.maxPerWallet,
    ethers.ZeroHash,
    config.royaltyReceiver || wallet.address,
    config.royaltyBps || 500,
    TREASURY_ADDRESS,
    wallet.address,
  );

  // Estimate gas for the large contract deployment
  const dataBytes = Math.floor(deployTx.data.length / 2);
  deployTx.gasLimit = estimateChunkGasLimit(dataBytes);
  console.log(`  Deploy data: ${dataBytes} bytes, gasLimit: ${deployTx.gasLimit}`);

  const tx = await wallet.sendTransaction(deployTx);
  const receipt = await tx.wait();

  if (receipt.status === 0) throw new Error(`NFT contract deployment reverted (gasUsed: ${receipt.gasUsed})`);

  const nftAddress = receipt.contractAddress;
  const code = await provider.getCode(nftAddress);
  if (!code || code.length <= 2) throw new Error('NFT contract deployment verification failed');
  console.log(`  ✅ NFT Contract: ${nftAddress}`);

  // Enable public minting
  console.log('  Enabling public minting...');
  const nft = new ethers.Contract(nftAddress, NFT_ABI, wallet);
  const setStateTx = await nft.setMintState(2, { gasLimit: 10_000_000n });
  await setStateTx.wait();
  console.log('  ✅ Minting enabled (public)');

  return nftAddress;
}

// ============================================================================
// DB Registration
// ============================================================================

async function registerToDB(nftAddress, containerId, ownerAddress, config) {
  console.log('\n📝 Phase 4: Registering to DB...');
  try {
    const res = await fetch(REGISTER_API, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        containerId,
        nftAddress,
        ownerAddress,
        name: config.name,
        symbol: config.symbol,
        maxSupply: config.maxSupply,
        mintState: 2,
        publicPrice: config.publicPrice || '0',
        wlPrice: config.whitelistPrice || '0',
        maxPerWallet: config.maxPerWallet,
        description: config.description,
      }),
    });
    const data = await res.json();
    if (data.success) {
      console.log('  ✅ Registered to Warren DB');
    } else {
      console.log(`  ⚠ DB registration: ${data.error || 'unknown error'}`);
    }
  } catch (e) {
    console.log(`  ⚠ DB registration failed (non-critical): ${e.message}`);
  }
}

// ============================================================================
// Main Deploy Flow
// ============================================================================

async function deploy(privateKey, images, config) {
  const provider = new ethers.JsonRpcProvider(RPC_URL, CHAIN_ID);
  const wallet = new ethers.Wallet(privateKey, provider);

  console.log('='.repeat(60));
  console.log('Warren NFT Collection Deploy');
  console.log('='.repeat(60));
  console.log(`Address:     ${wallet.address}`);
  console.log(`Network:     MegaETH Mainnet (Chain ${CHAIN_ID})`);
  console.log(`Collection:  ${config.name} (${config.symbol})`);
  console.log(`Images:      ${images.length}`);
  console.log(`Max Supply:  ${config.maxSupply}`);

  const balance = await provider.getBalance(wallet.address);
  console.log(`Balance:     ${ethers.formatEther(balance)} ETH`);
  if (balance === 0n) throw new Error('No ETH balance. You need real MegaETH ETH for mainnet deployment.');

  await ensureGenesisKey(wallet);

  // Phase 1: Deploy all images
  console.log(`\n📸 Phase 1: Deploying ${images.length} image(s)...`);
  const deployedImages = [];
  for (let i = 0; i < images.length; i++) {
    const img = images[i];
    if (img.buffer.length > 500 * 1024) throw new Error(`Image ${img.originalPath} exceeds 500KB limit`);
    const result = await deployImageData(wallet, provider, img.buffer, `[${i + 1}/${images.length}]`);
    deployedImages.push({ ...result, containerPath: img.containerPath });
  }

  const totalSize = deployedImages.reduce((sum, img) => sum + img.totalSize, 0);
  console.log(`  Total image data: ${(totalSize / 1024).toFixed(1)}KB`);

  // Phase 2: Mint container
  const containerId = await mintContainer(wallet, deployedImages);

  // Phase 3: Deploy NFT collection
  const nftAddress = await deployCollection(wallet, provider, containerId, config);

  // Phase 4: Register to DB
  await registerToDB(nftAddress, containerId, wallet.address, config);

  // Output
  const managementUrl = `https://thewarren.app/launchpad/${nftAddress}/`;
  const mintUrl = `https://thewarren.app/launchpad/${nftAddress}/mint`;

  console.log('\n' + '='.repeat(60));
  console.log('🎉 NFT Collection Deployed!');
  console.log('='.repeat(60));
  console.log(`NFT Contract:  ${nftAddress}`);
  console.log(`Container ID:  ${containerId}`);
  console.log(`Image Count:   ${images.length}`);
  console.log(`Max Supply:    ${config.maxSupply}`);
  console.log(`Public Price:  ${config.publicPrice || '0'} ETH`);
  console.log('');
  console.log(`📋 Management: ${managementUrl}`);
  console.log(`🎨 Mint Page:  ${mintUrl}`);
  console.log('='.repeat(60));

  return { nftAddress, containerId, imageCount: images.length, managementUrl, mintUrl };
}

// ============================================================================
// CLI
// ============================================================================

async function main() {
  const args = process.argv.slice(2);
  const getArg = (n) => { const i = args.indexOf(`--${n}`); return i >= 0 ? args[i + 1] : undefined; };
  const hasArg = (n) => args.includes(`--${n}`);

  if (hasArg('help') || hasArg('h')) {
    console.log(`
Warren NFT Collection Deploy - Deploy NFT collections on MegaETH

Usage:
  PRIVATE_KEY=0x... node deploy-nft.js --images-folder ./art/ --name "My NFT" --symbol "MNFT" [options]
  PRIVATE_KEY=0x... node deploy-nft.js --generate-svg 10 --name "Gen Art" --symbol "GART" [options]

Required:
  --images-folder <path>    Folder with images (1.png, 2.png, ...)
  --generate-svg <count>    Generate random SVG art instead of using files
  --name <string>           Collection name
  --symbol <string>         Collection symbol (3-5 chars)

Optional:
  --description <text>      Collection description (default: "On-chain NFT collection on Warren")
  --max-supply <number>     Max NFTs (default: image count)
  --whitelist-price <eth>   WL mint price in ETH (default: 0)
  --public-price <eth>      Public mint price in ETH (default: 0)
  --max-per-wallet <number> Mint limit per wallet (default: 10)
  --royalty-bps <number>    Royalty basis points (default: 500 = 5%)
  --private-key <key>       Wallet private key (or set PRIVATE_KEY env)

Prerequisites:
  1. bash setup.sh (install ethers.js)
  2. You need MegaETH mainnet ETH for gas
  3. 0xRabbit.agent Key auto-mints (free)
`);
    process.exit(0);
  }

  const privateKey = getArg('private-key') || process.env.PRIVATE_KEY;
  if (!privateKey) { console.error('Error: set PRIVATE_KEY env or use --private-key'); process.exit(1); }

  const name = getArg('name');
  const symbol = getArg('symbol');
  if (!name || !symbol) { console.error('Error: --name and --symbol are required'); process.exit(1); }

  // Get images
  let images;
  const imagesFolder = getArg('images-folder');
  const generateCount = getArg('generate-svg');

  if (imagesFolder) {
    images = discoverImages(imagesFolder);
    console.log(`Found ${images.length} images in ${imagesFolder}`);
  } else if (generateCount) {
    const count = parseInt(generateCount);
    if (isNaN(count) || count < 1 || count > 256) { console.error('Error: --generate-svg must be 1-256'); process.exit(1); }
    images = generateSVGs(count);
    console.log(`Generated ${count} SVG images`);
  } else {
    console.error('Error: provide --images-folder or --generate-svg');
    process.exit(1);
  }

  const config = {
    name,
    symbol,
    description: getArg('description') || 'On-chain NFT collection on Warren',
    maxSupply: parseInt(getArg('max-supply') || images.length),
    whitelistPrice: getArg('whitelist-price') || '0',
    publicPrice: getArg('public-price') || '0',
    maxPerWallet: parseInt(getArg('max-per-wallet') || '10'),
    royaltyBps: parseInt(getArg('royalty-bps') || '500'),
    royaltyReceiver: getArg('royalty-receiver'),
  };

  try {
    const result = await deploy(privateKey, images, config);
    console.log('\n--- JSON ---');
    console.log(JSON.stringify(result, null, 2));
  } catch (e) {
    console.error(`\n❌ Failed: ${e.message}`);
    process.exit(1);
  }
}

main();


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)