From 8028c380bc6e31c5b38cf644c1b6bbb2808ae54f Mon Sep 17 00:00:00 2001 From: pg-agent Date: Fri, 30 Jan 2026 05:37:39 -0800 Subject: [PATCH 1/2] feat(tokenomics): auto-calculate total_supply and burn registry token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove `total_supply` from JSON config - now auto-calculated from LP + distributions + premints. Burn the registry token after it's returned so circulating supply matches exactly what users specified. Changes: - Script auto-calculates total_supply from component amounts - Factory validation no longer includes ERC20_UNIT in total_needed - StreamToken burns the returned registry token after registration - Mock registries updated to simulate Ekubo's token return behavior - Tests updated for new supply calculation and burn behavior Token flow after changes: 1. Mint 1 token → Registry (for verification) 2. Registry returns 1 token → StreamToken 3. Burn 1 token (new) 4. Mint premints → Recipients 5. Mint remaining → Factory (= LP + distributions) Result: Circulating supply = exactly LP + distributions + premints Co-Authored-By: Claude Opus 4.5 --- packages/presets/src/stream_token.cairo | 8 +++- .../src/tests/mocks/mock_registry.cairo | 22 +++++++++-- .../presets/src/tests/test_stream_token.cairo | 25 +++++++++--- .../src/factory/stream_token_factory.cairo | 6 ++- .../src/tests/mocks/mock_registry.cairo | 22 +++++++++-- .../tokenomics/src/tests/test_factory.cairo | 6 +-- scripts/create_stream_token.sh | 39 +++++++++++++------ .../examples/summit_test_attack_potions.json | 32 +++++++++++++++ .../summit_test_extralife_potions.json | 33 ++++++++++++++++ .../examples/summit_test_poison_potions.json | 33 ++++++++++++++++ .../examples/summit_test_revive_potions.json | 33 ++++++++++++++++ scripts/examples/token_config.example.json | 32 +++++++++++++++ 12 files changed, 261 insertions(+), 30 deletions(-) create mode 100644 scripts/examples/summit_test_attack_potions.json create mode 100644 scripts/examples/summit_test_extralife_potions.json create mode 100644 scripts/examples/summit_test_poison_potions.json create mode 100644 scripts/examples/summit_test_revive_potions.json create mode 100644 scripts/examples/token_config.example.json diff --git a/packages/presets/src/stream_token.cairo b/packages/presets/src/stream_token.cairo index 4b53fc87..d8f77ed3 100644 --- a/packages/presets/src/stream_token.cairo +++ b/packages/presets/src/stream_token.cairo @@ -110,9 +110,12 @@ pub mod StreamToken { // Mint tokens to registry for registration (1 token = 10^18 units) self.erc20.mint(registry_address, ERC20_UNIT.into()); - // Register token with Ekubo + // Register token with Ekubo (registry returns the token after verification) self.stream.register_token(); + // Burn the returned registry token so circulating supply = exactly what user specified + self.erc20.burn(starknet::get_contract_address(), ERC20_UNIT.into()); + // Mint premint allocations directly to recipients let mut premint_total: u128 = 0; for premint in premint_allocations { @@ -129,7 +132,8 @@ pub mod StreamToken { // Mint remaining tokens to factory for distribution // Factory will transfer to positions contract for liquidity and distribution - let remaining_supply: u256 = (total_supply - ERC20_UNIT - premint_total).into(); + // (registry token was minted and burned, so remaining = total_supply - premints) + let remaining_supply: u256 = (total_supply - premint_total).into(); self.erc20.mint(factory, remaining_supply); } } diff --git a/packages/presets/src/tests/mocks/mock_registry.cairo b/packages/presets/src/tests/mocks/mock_registry.cairo index 7a63f6e5..e3512959 100644 --- a/packages/presets/src/tests/mocks/mock_registry.cairo +++ b/packages/presets/src/tests/mocks/mock_registry.cairo @@ -1,5 +1,5 @@ /// Mock Token Registry for testing StreamToken -/// Accepts register_token calls without any validation or external calls +/// Simulates Ekubo's registry behavior: accepts 1 token, verifies, and returns it use ekubo::interfaces::erc20::IERC20Dispatcher; @@ -12,7 +12,11 @@ pub trait IMockTokenRegistry { #[starknet::contract] pub mod MockTokenRegistry { use ekubo::interfaces::erc20::IERC20Dispatcher; + use openzeppelin_interfaces::token::erc20::{ + IERC20Dispatcher as OzIERC20Dispatcher, IERC20DispatcherTrait, + }; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use starknet::{get_caller_address, get_contract_address}; #[storage] struct Storage { @@ -22,8 +26,20 @@ pub mod MockTokenRegistry { #[abi(embed_v0)] impl MockTokenRegistryImpl of super::IMockTokenRegistry { fn register_token(ref self: ContractState, token: IERC20Dispatcher) { - // Just count registrations, don't do any validation - let _ = token; // Suppress unused warning + // Simulate Ekubo's registry behavior: + // 1. Receive 1 token from caller (already done by StreamToken minting to registry) + // 2. Verify token is valid (skip for mock) + // 3. Return 1 token back to the caller + let caller = get_caller_address(); + let this = get_contract_address(); + + // Use OZ dispatcher to transfer the token back to caller (like Ekubo does) + let oz_token = OzIERC20Dispatcher { contract_address: token.contract_address }; + let balance = oz_token.balance_of(this); + if balance > 0 { + oz_token.transfer(caller, balance); + } + let count = self.registered_count.read(); self.registered_count.write(count + 1); } diff --git a/packages/presets/src/tests/test_stream_token.cairo b/packages/presets/src/tests/test_stream_token.cairo index f76ad2bd..fa7f8baa 100644 --- a/packages/presets/src/tests/test_stream_token.cairo +++ b/packages/presets/src/tests/test_stream_token.cairo @@ -247,19 +247,22 @@ fn test_constructor_sets_decimals_to_18() { } #[test] -fn test_constructor_mints_one_token_to_registry() { +fn test_constructor_registry_token_is_burned() { let setup = deploy_stream_token(); + // Registry token is minted for verification then burned + // so registry should have 0 tokens after deployment let registry_balance = setup.erc20.balance_of(setup.registry); - assert!(registry_balance == ONE_TOKEN, "Registry should have 1 token"); + assert!(registry_balance == 0, "Registry should have 0 tokens (burned after registration)"); } #[test] fn test_constructor_mints_remaining_supply_to_factory() { let setup = deploy_stream_token(); - // Total supply is 10000 tokens, registry gets 1 - let expected_factory_balance: u256 = (10000_u128 * ERC20_UNIT - ERC20_UNIT).into(); + // Total supply is 10000 tokens, registry token is minted and burned + // so factory gets full total_supply (no premints in this test) + let expected_factory_balance: u256 = (10000_u128 * ERC20_UNIT).into(); let factory_balance = setup.erc20.balance_of(setup.factory); assert!(factory_balance == expected_factory_balance, "Factory balance mismatch"); } @@ -301,9 +304,21 @@ fn test_constructor_sets_deployment_state_to_zero() { fn test_total_supply() { let setup = deploy_stream_token(); + // Total supply should be exactly what the user specified (10000 tokens) + // The registry token mint+burn is a net zero effect on total supply let total_supply = setup.erc20.total_supply(); let expected: u256 = (10000_u128 * ERC20_UNIT).into(); - assert!(total_supply == expected, "Total supply mismatch"); + assert!(total_supply == expected, "Total supply should match user-specified amount"); +} + +#[test] +fn test_stream_token_contract_holds_zero_balance() { + let setup = deploy_stream_token(); + + // The StreamToken contract itself should hold 0 tokens + // (registry token was returned and burned) + let contract_balance = setup.erc20.balance_of(setup.token_address); + assert!(contract_balance == 0, "StreamToken contract should hold 0 tokens"); } #[test] diff --git a/packages/tokenomics/src/factory/stream_token_factory.cairo b/packages/tokenomics/src/factory/stream_token_factory.cairo index a344936c..07160244 100644 --- a/packages/tokenomics/src/factory/stream_token_factory.cairo +++ b/packages/tokenomics/src/factory/stream_token_factory.cairo @@ -28,7 +28,7 @@ pub mod StreamTokenFactory { }; use starknet::syscalls::deploy_syscall; use starknet::{ClassHash, ContractAddress, get_caller_address, get_contract_address}; - use crate::constants::{ERC20_UNIT, Errors}; + use crate::constants::Errors; // Embed Ownable component for admin functions component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); @@ -149,7 +149,9 @@ pub mod StreamTokenFactory { } let lp_amount = params.liquidity_config.stream_token_amount; - let total_needed = ERC20_UNIT + lp_amount + distribution_total + premint_total; + // total_supply should equal exactly LP + distributions + premints + // (registry token is minted then burned, so no extra needed) + let total_needed = lp_amount + distribution_total + premint_total; assert(params.total_supply >= total_needed, Errors::STREAM_SUPPLY_TOO_LOW); // Transfer paired tokens from caller to positions contract diff --git a/packages/tokenomics/src/tests/mocks/mock_registry.cairo b/packages/tokenomics/src/tests/mocks/mock_registry.cairo index 7a63f6e5..e3512959 100644 --- a/packages/tokenomics/src/tests/mocks/mock_registry.cairo +++ b/packages/tokenomics/src/tests/mocks/mock_registry.cairo @@ -1,5 +1,5 @@ /// Mock Token Registry for testing StreamToken -/// Accepts register_token calls without any validation or external calls +/// Simulates Ekubo's registry behavior: accepts 1 token, verifies, and returns it use ekubo::interfaces::erc20::IERC20Dispatcher; @@ -12,7 +12,11 @@ pub trait IMockTokenRegistry { #[starknet::contract] pub mod MockTokenRegistry { use ekubo::interfaces::erc20::IERC20Dispatcher; + use openzeppelin_interfaces::token::erc20::{ + IERC20Dispatcher as OzIERC20Dispatcher, IERC20DispatcherTrait, + }; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use starknet::{get_caller_address, get_contract_address}; #[storage] struct Storage { @@ -22,8 +26,20 @@ pub mod MockTokenRegistry { #[abi(embed_v0)] impl MockTokenRegistryImpl of super::IMockTokenRegistry { fn register_token(ref self: ContractState, token: IERC20Dispatcher) { - // Just count registrations, don't do any validation - let _ = token; // Suppress unused warning + // Simulate Ekubo's registry behavior: + // 1. Receive 1 token from caller (already done by StreamToken minting to registry) + // 2. Verify token is valid (skip for mock) + // 3. Return 1 token back to the caller + let caller = get_caller_address(); + let this = get_contract_address(); + + // Use OZ dispatcher to transfer the token back to caller (like Ekubo does) + let oz_token = OzIERC20Dispatcher { contract_address: token.contract_address }; + let balance = oz_token.balance_of(this); + if balance > 0 { + oz_token.transfer(caller, balance); + } + let count = self.registered_count.read(); self.registered_count.write(count + 1); } diff --git a/packages/tokenomics/src/tests/test_factory.cairo b/packages/tokenomics/src/tests/test_factory.cairo index a9d4b299..6e14a9c7 100644 --- a/packages/tokenomics/src/tests/test_factory.cairo +++ b/packages/tokenomics/src/tests/test_factory.cairo @@ -407,7 +407,7 @@ fn test_create_token_supply_too_low_fails() { }, ]; - // Supply = 100, but need: ERC20_UNIT + 1000 (LP) + 500 (distribution) = 1501 tokens + // Supply = 100, but need: 1000 (LP) + 500 (distribution) = 1500 tokens let params = CreateTokenParams { name: "Test", symbol: "TST", @@ -560,7 +560,7 @@ fn create_params_with_premints( premint_total += *premint.amount; } - // Supply needs to cover: ERC20_UNIT (1) + LP (1000) + distribution (500) + premints + // Supply needs to cover: LP (1000) + distribution (500) + premints let base_supply: u128 = 10000_u128 * 1_000_000_000_000_000_000; let total_supply: u128 = base_supply + premint_total; @@ -610,7 +610,7 @@ fn test_create_token_with_premints_supply_too_low_fails() { ]; // Premints that push total over the supply limit - // Total needed: ERC20_UNIT (1) + LP (1000) + distribution (500) + premints (1000) = 2501+ + // Total needed: LP (1000) + distribution (500) + premints (1000) = 2500 // Supply provided: 2000 tokens - NOT ENOUGH let premint_allocations: Array = array![ PremintAllocation { recipient: USER1(), amount: 500_u128 * 1_000_000_000_000_000_000 }, diff --git a/scripts/create_stream_token.sh b/scripts/create_stream_token.sh index f22be325..8b1b9a15 100755 --- a/scripts/create_stream_token.sh +++ b/scripts/create_stream_token.sh @@ -12,6 +12,7 @@ # - Config values are human-readable (e.g., "1000000" = 1 million tokens) # - The script automatically converts to wei (multiplies by 10^18) # - Initial tick is calculated automatically by the StreamToken contract +# - total_supply is auto-calculated: LP + distributions + premints # # PRICE CALCULATION: # The initial pool price is derived from the liquidity amounts you provide: @@ -106,9 +107,6 @@ check_dependencies() { if ! command -v xxd &> /dev/null; then missing+=("xxd (part of vim or xxd package)") fi - if ! command -v bc &> /dev/null; then - missing+=("bc") - fi if [ ${#missing[@]} -ne 0 ]; then print_error "Missing required dependencies:" @@ -116,8 +114,8 @@ check_dependencies() { echo " - $dep" done echo "" - echo "Install on macOS: brew install jq xxd bc" - echo "Install on Ubuntu: apt install jq xxd bc curl" + echo "Install on macOS: brew install jq xxd" + echo "Install on Ubuntu: apt install jq xxd curl" exit 1 fi } @@ -493,7 +491,6 @@ CONFIG=$(cat "$CONFIG_FILE") # Extract and validate required fields TOKEN_NAME=$(echo "$CONFIG" | jq -r '.name') TOKEN_SYMBOL=$(echo "$CONFIG" | jq -r '.symbol') -TOTAL_SUPPLY=$(echo "$CONFIG" | jq -r '.total_supply') if [ "$TOKEN_NAME" == "null" ] || [ -z "$TOKEN_NAME" ]; then print_error "Missing required field: name" @@ -505,11 +502,6 @@ if [ "$TOKEN_SYMBOL" == "null" ] || [ -z "$TOKEN_SYMBOL" ]; then exit 1 fi -if [ "$TOTAL_SUPPLY" == "null" ] || [ -z "$TOTAL_SUPPLY" ]; then - print_error "Missing required field: total_supply" - exit 1 -fi - # Extract liquidity config PAIRED_TOKEN=$(echo "$CONFIG" | jq -r '.liquidity_config.paired_token') POOL_FEE=$(echo "$CONFIG" | jq -r '.liquidity_config.fee') @@ -534,7 +526,6 @@ if [ "$PAIRED_TOKEN_AMOUNT" == "null" ] || [ -z "$PAIRED_TOKEN_AMOUNT" ]; then fi # Convert human-readable amounts to wei (18 decimals) -TOTAL_SUPPLY_WEI=$(to_wei "$TOTAL_SUPPLY") STREAM_TOKEN_AMOUNT_WEI=$(to_wei "$STREAM_TOKEN_AMOUNT") PAIRED_TOKEN_AMOUNT_WEI=$(to_wei "$PAIRED_TOKEN_AMOUNT") @@ -545,6 +536,30 @@ MIN_LIQUIDITY="${MIN_LIQUIDITY:-0}" ORDER_COUNT=$(echo "$CONFIG" | jq '.distribution_orders | length') PREMINT_COUNT=$(echo "$CONFIG" | jq '.premint_allocations | length') +# Calculate distribution total +DISTRIBUTION_TOTAL=0 +for i in $(seq 0 $((ORDER_COUNT - 1))); do + local_amount=$(echo "$CONFIG" | jq -r ".distribution_orders[$i].amount") + DISTRIBUTION_TOTAL=$((DISTRIBUTION_TOTAL + local_amount)) +done + +# Calculate premint total +PREMINT_TOTAL=0 +for i in $(seq 0 $((PREMINT_COUNT - 1))); do + local_amount=$(echo "$CONFIG" | jq -r ".premint_allocations[$i].amount") + PREMINT_TOTAL=$((PREMINT_TOTAL + local_amount)) +done + +# Auto-calculate total_supply: LP + distributions + premints +# (registry token is minted and burned during deployment, so no extra needed) +TOTAL_SUPPLY=$((STREAM_TOKEN_AMOUNT + DISTRIBUTION_TOTAL + PREMINT_TOTAL)) +TOTAL_SUPPLY_WEI=$(to_wei "$TOTAL_SUPPLY") + +print_info "Auto-calculated total_supply: $TOTAL_SUPPLY tokens" +print_verbose " LP tokens: $STREAM_TOKEN_AMOUNT" +print_verbose " Distribution tokens: $DISTRIBUTION_TOTAL" +print_verbose " Premint tokens: $PREMINT_TOTAL" + if [ "$ORDER_COUNT" -eq 0 ]; then print_error "At least one distribution order is required" exit 1 diff --git a/scripts/examples/summit_test_attack_potions.json b/scripts/examples/summit_test_attack_potions.json new file mode 100644 index 00000000..dbdd16c4 --- /dev/null +++ b/scripts/examples/summit_test_attack_potions.json @@ -0,0 +1,32 @@ +{ + "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens). total_supply is auto-calculated from LP + distributions + premints.", + + "name": "TATKA", + "symbol": "TATKA", + + "liquidity_config": { + "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "stream_token_amount": "100000", + "paired_token_amount": "1000" + }, + + "distribution_orders": [ + { + "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", + "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "start_time": 0, + "end_time": 1777336320, + "amount": "6000000", + "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" + } + ], + + "premint_allocations": [ + { + "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", + "amount": "1" + } + ] +} diff --git a/scripts/examples/summit_test_extralife_potions.json b/scripts/examples/summit_test_extralife_potions.json new file mode 100644 index 00000000..c9bd3e24 --- /dev/null +++ b/scripts/examples/summit_test_extralife_potions.json @@ -0,0 +1,33 @@ +{ + "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens).", + + "name": "TEXLA", + "symbol": "TEXLA", + "total_supply": "305003", + + "liquidity_config": { + "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "stream_token_amount": "5000", + "paired_token_amount": "1000" + }, + + "distribution_orders": [ + { + "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", + "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "start_time": 0, + "end_time": 1777336320, + "amount": "300000", + "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" + } + ], + + "premint_allocations": [ + { + "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", + "amount": "1" + } + ] +} diff --git a/scripts/examples/summit_test_poison_potions.json b/scripts/examples/summit_test_poison_potions.json new file mode 100644 index 00000000..404c5084 --- /dev/null +++ b/scripts/examples/summit_test_poison_potions.json @@ -0,0 +1,33 @@ +{ + "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens).", + + "name": "TPOISONA", + "symbol": "TPOISONA", + "total_supply": "6100003", + + "liquidity_config": { + "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "stream_token_amount": "100000", + "paired_token_amount": "1000" + }, + + "distribution_orders": [ + { + "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", + "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "start_time": 0, + "end_time": 1777336320, + "amount": "6000000", + "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" + } + ], + + "premint_allocations": [ + { + "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", + "amount": "1" + } + ] +} diff --git a/scripts/examples/summit_test_revive_potions.json b/scripts/examples/summit_test_revive_potions.json new file mode 100644 index 00000000..402c29ab --- /dev/null +++ b/scripts/examples/summit_test_revive_potions.json @@ -0,0 +1,33 @@ +{ + "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens).", + + "name": "TREVIVEA", + "symbol": "TREVIVEA", + "total_supply": "6100003", + + "liquidity_config": { + "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "stream_token_amount": "100000", + "paired_token_amount": "1000" + }, + + "distribution_orders": [ + { + "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", + "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "17014118346046924117642026945517453312", + "start_time": 0, + "end_time": 1777336320, + "amount": "6000000", + "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" + } + ], + + "premint_allocations": [ + { + "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", + "amount": "1" + } + ] +} diff --git a/scripts/examples/token_config.example.json b/scripts/examples/token_config.example.json new file mode 100644 index 00000000..01be31d6 --- /dev/null +++ b/scripts/examples/token_config.example.json @@ -0,0 +1,32 @@ +{ + "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens). total_supply is auto-calculated from LP + distributions + premints.", + + "name": "TSTATTACKONE", + "symbol": "TSTATTACKONE", + + "liquidity_config": { + "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", + "fee": "170141183460469235273462165868118016", + "stream_token_amount": "5000", + "paired_token_amount": "500" + }, + + "distribution_orders": [ + { + "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", + "buy_token": "0x042DD777885AD2C116be96d4D634abC90A26A790ffB5871E037Dd5Ae7d2Ec86B", + "fee": "170141183460469235273462165868118016", + "start_time": 0, + "end_time": 1811939328, + "amount": "300000", + "proceeds_recipient": "0xYOUR_TREASURY_ADDRESS_HERE" + } + ], + + "premint_allocations": [ + { + "recipient": "0x28c5a99082ec6b142ea6f7cc3b046f4effc8c13077ad97cd45c993fe4cd429d", + "amount": "5000" + } + ] +} From 84bd30a1f41009ac893cb2c7ed3898517931e67f Mon Sep 17 00:00:00 2001 From: pg-agent Date: Fri, 30 Jan 2026 05:54:20 -0800 Subject: [PATCH 2/2] fix(script): use jq one-liners for total calculations Address PR review feedback: - Replace loop-based distribution/premint totals with jq one-liners that handle empty arrays gracefully with `// 0` default - Remove summit_test_*.json from tracking (add to .gitignore) - Keep only token_config.example.json as the committed example Co-Authored-By: Claude Opus 4.5 --- .gitignore | 5 ++- scripts/create_stream_token.sh | 16 ++------- .../examples/summit_test_attack_potions.json | 32 ------------------ .../summit_test_extralife_potions.json | 33 ------------------- .../examples/summit_test_poison_potions.json | 33 ------------------- .../examples/summit_test_revive_potions.json | 33 ------------------- scripts/examples/token_config.example.json | 16 ++++++--- 7 files changed, 19 insertions(+), 149 deletions(-) delete mode 100644 scripts/examples/summit_test_attack_potions.json delete mode 100644 scripts/examples/summit_test_extralife_potions.json delete mode 100644 scripts/examples/summit_test_poison_potions.json delete mode 100644 scripts/examples/summit_test_revive_potions.json diff --git a/.gitignore b/.gitignore index ee075bf2..232ae6f1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,7 @@ packages/test_dojo/ coverage.lcov **/snfoundry_trace/ **/coverage_html/ -**/coverage/ \ No newline at end of file +**/coverage/ + +# Example configs (only token_config.example.json should be committed) +scripts/examples/summit_test_*.json \ No newline at end of file diff --git a/scripts/create_stream_token.sh b/scripts/create_stream_token.sh index 8b1b9a15..aca1cac4 100755 --- a/scripts/create_stream_token.sh +++ b/scripts/create_stream_token.sh @@ -536,19 +536,9 @@ MIN_LIQUIDITY="${MIN_LIQUIDITY:-0}" ORDER_COUNT=$(echo "$CONFIG" | jq '.distribution_orders | length') PREMINT_COUNT=$(echo "$CONFIG" | jq '.premint_allocations | length') -# Calculate distribution total -DISTRIBUTION_TOTAL=0 -for i in $(seq 0 $((ORDER_COUNT - 1))); do - local_amount=$(echo "$CONFIG" | jq -r ".distribution_orders[$i].amount") - DISTRIBUTION_TOTAL=$((DISTRIBUTION_TOTAL + local_amount)) -done - -# Calculate premint total -PREMINT_TOTAL=0 -for i in $(seq 0 $((PREMINT_COUNT - 1))); do - local_amount=$(echo "$CONFIG" | jq -r ".premint_allocations[$i].amount") - PREMINT_TOTAL=$((PREMINT_TOTAL + local_amount)) -done +# Calculate distribution and premint totals using jq (handles empty arrays gracefully) +DISTRIBUTION_TOTAL=$(echo "$CONFIG" | jq -r '[.distribution_orders[].amount | tonumber] | add // 0') +PREMINT_TOTAL=$(echo "$CONFIG" | jq -r '[.premint_allocations[].amount | tonumber] | add // 0') # Auto-calculate total_supply: LP + distributions + premints # (registry token is minted and burned during deployment, so no extra needed) diff --git a/scripts/examples/summit_test_attack_potions.json b/scripts/examples/summit_test_attack_potions.json deleted file mode 100644 index dbdd16c4..00000000 --- a/scripts/examples/summit_test_attack_potions.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens). total_supply is auto-calculated from LP + distributions + premints.", - - "name": "TATKA", - "symbol": "TATKA", - - "liquidity_config": { - "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "stream_token_amount": "100000", - "paired_token_amount": "1000" - }, - - "distribution_orders": [ - { - "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", - "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "start_time": 0, - "end_time": 1777336320, - "amount": "6000000", - "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" - } - ], - - "premint_allocations": [ - { - "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", - "amount": "1" - } - ] -} diff --git a/scripts/examples/summit_test_extralife_potions.json b/scripts/examples/summit_test_extralife_potions.json deleted file mode 100644 index c9bd3e24..00000000 --- a/scripts/examples/summit_test_extralife_potions.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens).", - - "name": "TEXLA", - "symbol": "TEXLA", - "total_supply": "305003", - - "liquidity_config": { - "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "stream_token_amount": "5000", - "paired_token_amount": "1000" - }, - - "distribution_orders": [ - { - "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", - "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "start_time": 0, - "end_time": 1777336320, - "amount": "300000", - "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" - } - ], - - "premint_allocations": [ - { - "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", - "amount": "1" - } - ] -} diff --git a/scripts/examples/summit_test_poison_potions.json b/scripts/examples/summit_test_poison_potions.json deleted file mode 100644 index 404c5084..00000000 --- a/scripts/examples/summit_test_poison_potions.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens).", - - "name": "TPOISONA", - "symbol": "TPOISONA", - "total_supply": "6100003", - - "liquidity_config": { - "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "stream_token_amount": "100000", - "paired_token_amount": "1000" - }, - - "distribution_orders": [ - { - "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", - "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "start_time": 0, - "end_time": 1777336320, - "amount": "6000000", - "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" - } - ], - - "premint_allocations": [ - { - "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", - "amount": "1" - } - ] -} diff --git a/scripts/examples/summit_test_revive_potions.json b/scripts/examples/summit_test_revive_potions.json deleted file mode 100644 index 402c29ab..00000000 --- a/scripts/examples/summit_test_revive_potions.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens).", - - "name": "TREVIVEA", - "symbol": "TREVIVEA", - "total_supply": "6100003", - - "liquidity_config": { - "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "stream_token_amount": "100000", - "paired_token_amount": "1000" - }, - - "distribution_orders": [ - { - "_comment": "TWAMM end_time must be aligned to powers of 16. Script validates and suggests valid times.", - "buy_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", - "fee": "17014118346046924117642026945517453312", - "start_time": 0, - "end_time": 1777336320, - "amount": "6000000", - "proceeds_recipient": "0x04f069785b8d6b302fdae9516dbbf8149d6af7e89763702166a58bae1a9eaa8b" - } - ], - - "premint_allocations": [ - { - "recipient": "0x03c0f67740e3fe298a52fe75dd24b4981217406f133e0835331379731b67dc92", - "amount": "1" - } - ] -} diff --git a/scripts/examples/token_config.example.json b/scripts/examples/token_config.example.json index 01be31d6..f4467655 100644 --- a/scripts/examples/token_config.example.json +++ b/scripts/examples/token_config.example.json @@ -1,8 +1,8 @@ { "_comment": "All token amounts assume 18 decimals. Use human-readable values (e.g., '1000000' for 1M tokens). total_supply is auto-calculated from LP + distributions + premints.", - "name": "TSTATTACKONE", - "symbol": "TSTATTACKONE", + "name": "TOKEN_NAME", + "symbol": "TOKEN_SYMBOL", "liquidity_config": { "paired_token": "0x03C8559b31A325f9f45Ce98f709e8e7C655805C6ca4EECB78FF7761F202AcBA3", @@ -25,8 +25,16 @@ "premint_allocations": [ { - "recipient": "0x28c5a99082ec6b142ea6f7cc3b046f4effc8c13077ad97cd45c993fe4cd429d", - "amount": "5000" + "recipient": "0xPREMINT_RECIPIENT_ADDRESS", + "amount": "PREMINT_AMOUNT" + }, + { + "recipient": "0xPREMINT_RECIPIENT_ADDRESS2", + "amount": "PREMINT_AMOUNT" + }, + { + "recipient": "0xPREMINT_RECIPIENT_ADDRESS3", + "amount": "PREMINT_AMOUNT" } ] }