diff --git a/.oxfmtrc.json b/.oxfmtrc.json index f77d99b..c6c2c4e 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -3,5 +3,5 @@ "trailingComma": "all", "printWidth": 80, "sortPackageJson": false, - "ignorePatterns": ["openapi.json"] + "ignorePatterns": ["openapi.json", "src/routes/launches/vectors/**"] } diff --git a/openapi.json b/openapi.json index b0a5df2..9c4f6ce 100644 --- a/openapi.json +++ b/openapi.json @@ -9935,6 +9935,2460 @@ } } }, + "/launches": { + "get": { + "tags": [ + "Launches" + ], + "operationId": "get_ListLaunches", + "summary": "List supported zero-seed launches across chains, with status, owner and creator filters, ordering and market aggregates", + "parameters": [ + { + "schema": { + "type": "integer", + "format": "int64" + }, + "required": false, + "name": "chainId", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "all", + "trading", + "upcoming" + ], + "default": "all" + }, + "required": false, + "name": "status", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^0x[a-fA-F0-9]+$", + "description": "A hexadecimal number" + }, + { + "type": "string", + "pattern": "^\\d+$", + "description": "A decimal number" + } + ], + "title": "Address", + "description": "An address on the specified blockchain network" + }, + "required": false, + "description": "An address on the specified blockchain network", + "name": "owner", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^0x[a-fA-F0-9]+$", + "description": "A hexadecimal number" + }, + { + "type": "string", + "pattern": "^\\d+$", + "description": "A decimal number" + } + ], + "title": "Address", + "description": "An address on the specified blockchain network" + }, + "required": false, + "description": "An address on the specified blockchain network", + "name": "creator", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "market_cap", + "volume", + "sold_share", + "trade_count", + "created" + ], + "default": "market_cap", + "description": "Descending, over every launch matching the filters before offset and limit; ties newest first. market_cap and volume rank launches with a USD value first, by USD, then the rest by whole quote units (raw / 10^decimals); created is newest first" + }, + "required": false, + "description": "Descending, over every launch matching the filters before offset and limit; ties newest first. market_cap and volume rank launches with a USD value first, by USD, then the rest by whole quote units (raw / 10^decimals); created is newest first", + "name": "order_by", + "in": "query" + }, + { + "schema": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "maximum": 100000, + "default": 0 + }, + "required": false, + "name": "offset", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexed zero-seed launch data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "zero-seed-launch-api/v7" + ] + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "zero-seed-launch-api/v7" + ] + }, + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "pool_id": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "pool_key": { + "type": "object", + "properties": { + "core_address": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "token0": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "token1": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "config": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "fee": { + "type": "string", + "enum": [ + "0" + ] + }, + "tick_spacing": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "extension": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + } + }, + "required": [ + "core_address", + "token0", + "token1", + "config", + "fee", + "tick_spacing", + "extension" + ], + "additionalProperties": false + }, + "token": { + "type": "object", + "properties": { + "address": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "symbol": { + "type": [ + "string", + "null" + ] + }, + "decimals": { + "type": "number", + "enum": [ + 18 + ] + } + }, + "required": [ + "address", + "name", + "symbol", + "decimals" + ], + "additionalProperties": false + }, + "quote_token": { + "type": "object", + "properties": { + "address": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "symbol": { + "type": [ + "string", + "null" + ] + }, + "decimals": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "maximum": 255 + }, + "kind": { + "type": "string", + "enum": [ + "native", + "erc20" + ] + } + }, + "required": [ + "address", + "name", + "symbol", + "decimals", + "kind" + ], + "additionalProperties": false + }, + "launch_token_is_token1": { + "type": "boolean" + }, + "controller": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "creator": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "owner": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "logo_url": { + "type": [ + "string", + "null" + ], + "description": "LaunchCreated.logoUrl exactly as emitted; null when empty or not valid UTF-8. Untrusted: never fetched or rewritten here" + }, + "parameters": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "symbol": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "supply": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "quote_token": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "ask_tick": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "upper_tick": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "trading_start": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$" + }, + "decay_rate_x32": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$" + }, + "initial_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "final_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "salt": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "name", + "symbol", + "supply", + "quote_token", + "ask_tick", + "upper_tick", + "trading_start", + "decay_rate_x32", + "initial_fee", + "final_fee", + "salt" + ], + "additionalProperties": false + }, + "range": { + "type": "object", + "properties": { + "tick_spacing": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "aligned_ask_tick": { + "type": "integer" + }, + "aligned_upper_tick": { + "type": "integer" + }, + "pool_tick_lower": { + "type": "integer" + }, + "pool_tick_upper": { + "type": "integer" + } + }, + "required": [ + "tick_spacing", + "aligned_ask_tick", + "aligned_upper_tick", + "pool_tick_lower", + "pool_tick_upper" + ], + "additionalProperties": false + }, + "supply": { + "type": "object", + "properties": { + "requested": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "installed": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "sink": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "sink_holder": { + "type": "string", + "enum": [ + "0x0000000000000000000000000000000000000000" + ] + } + }, + "required": [ + "requested", + "installed", + "sink", + "sink_holder" + ], + "additionalProperties": false + }, + "trading_start": { + "type": "integer", + "minimum": 0 + }, + "status": { + "type": "string", + "enum": [ + "upcoming", + "trading" + ], + "description": "upcoming while evaluated_at < trading_start, else trading" + }, + "fee_schedule": { + "type": "object", + "properties": { + "trading_start": { + "type": "integer", + "minimum": 0 + }, + "initial_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "final_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "decay_rate_x32": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "decayRateX32: unsigned Q32.32 ticks per second as a canonical decimal uint64; 0 keeps initial_fee" + }, + "half_life_seconds": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "Half-life of the excess over the floor, seconds with 6 decimals (floored); null for rate 0. Display only" + }, + "saturation_elapsed_seconds": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)$", + "description": "floor(381061679028371455 / decay_rate_x32): after this many seconds the fee is exactly final_fee; null for rate 0" + }, + "phase": { + "type": "string", + "enum": [ + "before_trading_start", + "decaying", + "at_floor", + "constant" + ] + }, + "fee_rate": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "evaluated_at": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "trading_start", + "initial_fee", + "final_fee", + "decay_rate_x32", + "half_life_seconds", + "saturation_elapsed_seconds", + "phase", + "fee_rate", + "evaluated_at" + ], + "additionalProperties": false + }, + "market": { + "type": "object", + "properties": { + "price_tick": { + "type": "integer" + }, + "price_x128": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "market_cap": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "floor(price * totalSupply) in raw quote units; totalSupply includes the sink" + }, + "market_cap_usd": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "market_cap / 10^quote decimals * the indexed quote USD price, rounded to 6 decimals; null when the quote has no indexed price or no known decimals" + }, + "raised": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Quote held by the launch pool (buyers' net input)" + }, + "sold": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "installed - launch tokens left in the pool" + }, + "sold_share": { + "type": "string", + "pattern": "^[01]\\.[0-9]{18}$", + "description": "sold / installed, 18 decimals, floored" + }, + "trade_count": { + "type": "integer", + "minimum": 0, + "description": "LaunchSwapped events of the launch, zero fills included" + }, + "volume": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Sum of |quote delta| over every LaunchSwapped of the launch, buys and sells, fee-inclusive, in raw quote base units" + }, + "volume_usd": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "volume / 10^quote decimals * the indexed quote USD price, rounded to 6 decimals; null exactly when market_cap_usd is" + } + }, + "required": [ + "price_tick", + "price_x128", + "market_cap", + "market_cap_usd", + "raised", + "sold", + "sold_share", + "trade_count", + "volume", + "volume_usd" + ], + "additionalProperties": false + }, + "created": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + }, + "event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "transaction_index": { + "type": "integer", + "minimum": 0 + }, + "event_index": { + "type": "integer", + "minimum": 0 + }, + "transaction_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "block_number", + "block_hash", + "block_time", + "event_id", + "transaction_index", + "event_index", + "transaction_hash" + ], + "additionalProperties": false + }, + "as_of": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "block_number", + "block_hash", + "block_time" + ], + "additionalProperties": false + } + }, + "required": [ + "schema_version", + "chain_id", + "pool_id", + "pool_key", + "token", + "quote_token", + "launch_token_is_token1", + "controller", + "creator", + "owner", + "logo_url", + "parameters", + "range", + "supply", + "trading_start", + "status", + "fee_schedule", + "market", + "created", + "as_of" + ], + "additionalProperties": false + } + }, + "total": { + "type": "integer", + "minimum": 0 + }, + "totals": { + "type": "object", + "properties": { + "all": { + "type": "integer", + "minimum": 0 + }, + "trading": { + "type": "integer", + "minimum": 0 + }, + "upcoming": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "all", + "trading", + "upcoming" + ], + "additionalProperties": false + }, + "aggregates": { + "type": "object", + "properties": { + "launch_count": { + "type": "integer", + "minimum": 0 + }, + "trade_count": { + "type": "integer", + "minimum": 0 + }, + "by_quote": { + "type": "array", + "items": { + "type": "object", + "properties": { + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "quote_token": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "launch_count": { + "type": "integer", + "minimum": 0 + }, + "trade_count": { + "type": "integer", + "minimum": 0 + }, + "volume": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Sum of market.volume, raw quote units" + }, + "market_cap": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Sum of market.market_cap, raw quote units" + }, + "usd_priced": { + "type": "boolean", + "description": "The quote has an indexed USD price and known decimals" + }, + "volume_usd": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$" + }, + "market_cap_usd": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$" + } + }, + "required": [ + "chain_id", + "quote_token", + "launch_count", + "trade_count", + "volume", + "market_cap", + "usd_priced", + "volume_usd", + "market_cap_usd" + ], + "additionalProperties": false + } + }, + "usd": { + "type": "object", + "properties": { + "volume": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "Sum of market.volume_usd over priced launches; null when none is priced" + }, + "market_cap": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "Sum of market.market_cap_usd over priced launches; null when none is priced" + }, + "priced_launch_count": { + "type": "integer", + "minimum": 0 + }, + "excluded_launch_count": { + "type": "integer", + "minimum": 0, + "description": "Launches left out of the USD sums because their quote has no indexed price" + } + }, + "required": [ + "volume", + "market_cap", + "priced_launch_count", + "excluded_launch_count" + ], + "additionalProperties": false + } + }, + "required": [ + "launch_count", + "trade_count", + "by_quote", + "usd" + ], + "additionalProperties": false, + "description": "Over every launch matching all filters (the set total counts), not one page. by_quote is ordered by chain_id, then quote_token" + }, + "next_offset": { + "type": [ + "integer", + "null" + ], + "exclusiveMinimum": 0 + }, + "evaluated_at": { + "type": "integer", + "minimum": 0 + }, + "heads": { + "type": "array", + "items": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + }, + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } + }, + "required": [ + "block_number", + "block_hash", + "block_time", + "chain_id" + ], + "additionalProperties": false + } + } + }, + "required": [ + "schema_version", + "data", + "total", + "totals", + "aggregates", + "next_offset", + "evaluated_at", + "heads" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "The request parameters are invalid", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "The requested resource was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "An unexpected server error occurred", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "The indexed head is missing, inconsistent or stale", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/launches/{chainId}/{poolId}/claims": { + "get": { + "tags": [ + "Launches" + ], + "operationId": "get_ListLaunchClaims", + "summary": "List creator fee claims, one row per claim (extension event, periphery owner and recipient)", + "parameters": [ + { + "schema": { + "type": "integer", + "format": "int64" + }, + "required": true, + "name": "chainId", + "in": "path" + }, + { + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^0x[a-fA-F0-9]+$", + "description": "A hexadecimal number" + }, + { + "type": "string", + "pattern": "^\\d+$", + "description": "A decimal number" + } + ], + "title": "Numeric", + "description": "A number represented in hexadecimal or decimal" + }, + "required": true, + "description": "A number represented in hexadecimal or decimal", + "name": "poolId", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "after_event_id", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexed zero-seed launch data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "zero-seed-launch-api/v7" + ] + }, + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "pool_id": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "next_cursor": { + "type": [ + "string", + "null" + ] + }, + "as_of": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "block_number", + "block_hash", + "block_time" + ], + "additionalProperties": false + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "event": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + }, + "event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "transaction_index": { + "type": "integer", + "minimum": 0 + }, + "event_index": { + "type": "integer", + "minimum": 0 + }, + "transaction_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "block_number", + "block_hash", + "block_time", + "event_id", + "transaction_index", + "event_index", + "transaction_hash" + ], + "additionalProperties": false + }, + "payout_event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "owner": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "recipient": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "launch_token_amount": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "quote_token_amount": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } + }, + "required": [ + "event", + "payout_event_id", + "owner", + "recipient", + "launch_token_amount", + "quote_token_amount" + ], + "additionalProperties": false + } + }, + "totals": { + "type": "object", + "properties": { + "launch_token": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "quote_token": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } + }, + "required": [ + "launch_token", + "quote_token" + ], + "additionalProperties": false + } + }, + "required": [ + "schema_version", + "chain_id", + "pool_id", + "next_cursor", + "as_of", + "data", + "totals" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "The request parameters are invalid", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "The requested resource was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "An unexpected server error occurred", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "The indexed head is missing, inconsistent or stale", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/launches/{chainId}/{poolId}/owners": { + "get": { + "tags": [ + "Launches" + ], + "operationId": "get_ListLaunchOwners", + "summary": "List the creation owner and every later ownership transfer", + "parameters": [ + { + "schema": { + "type": "integer", + "format": "int64" + }, + "required": true, + "name": "chainId", + "in": "path" + }, + { + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^0x[a-fA-F0-9]+$", + "description": "A hexadecimal number" + }, + { + "type": "string", + "pattern": "^\\d+$", + "description": "A decimal number" + } + ], + "title": "Numeric", + "description": "A number represented in hexadecimal or decimal" + }, + "required": true, + "description": "A number represented in hexadecimal or decimal", + "name": "poolId", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "after_event_id", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexed zero-seed launch data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "zero-seed-launch-api/v7" + ] + }, + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "pool_id": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "next_cursor": { + "type": [ + "string", + "null" + ] + }, + "as_of": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "block_number", + "block_hash", + "block_time" + ], + "additionalProperties": false + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "event": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + }, + "event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "transaction_index": { + "type": "integer", + "minimum": 0 + }, + "event_index": { + "type": "integer", + "minimum": 0 + }, + "transaction_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "block_number", + "block_hash", + "block_time", + "event_id", + "transaction_index", + "event_index", + "transaction_hash" + ], + "additionalProperties": false + }, + "previous_owner": { + "type": [ + "string", + "null" + ], + "pattern": "^0x[0-9a-f]{40}$" + }, + "new_owner": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + } + }, + "required": [ + "event", + "previous_owner", + "new_owner" + ], + "additionalProperties": false + } + } + }, + "required": [ + "schema_version", + "chain_id", + "pool_id", + "next_cursor", + "as_of", + "data" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "The request parameters are invalid", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "The requested resource was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "An unexpected server error occurred", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "The indexed head is missing, inconsistent or stale", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/launches/{chainId}/{poolId}/swaps": { + "get": { + "tags": [ + "Launches" + ], + "operationId": "get_ListLaunchSwaps", + "summary": "List swaps; forwarding lockers are contracts, not users", + "parameters": [ + { + "schema": { + "type": "integer", + "format": "int64" + }, + "required": true, + "name": "chainId", + "in": "path" + }, + { + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^0x[a-fA-F0-9]+$", + "description": "A hexadecimal number" + }, + { + "type": "string", + "pattern": "^\\d+$", + "description": "A decimal number" + } + ], + "title": "Numeric", + "description": "A number represented in hexadecimal or decimal" + }, + "required": true, + "description": "A number represented in hexadecimal or decimal", + "name": "poolId", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "after_event_id", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexed zero-seed launch data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "zero-seed-launch-api/v7" + ] + }, + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "pool_id": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "next_cursor": { + "type": [ + "string", + "null" + ] + }, + "as_of": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "block_number", + "block_hash", + "block_time" + ], + "additionalProperties": false + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "event": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + }, + "event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "transaction_index": { + "type": "integer", + "minimum": 0 + }, + "event_index": { + "type": "integer", + "minimum": 0 + }, + "transaction_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "block_number", + "block_hash", + "block_time", + "event_id", + "transaction_index", + "event_index", + "transaction_hash" + ], + "additionalProperties": false + }, + "forwarding_locker": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "direction": { + "type": "string", + "enum": [ + "buy", + "sell", + "zero_fill" + ] + }, + "launch_token_delta": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "quote_token_delta": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "fee_rate": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "fee_amount": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "fee_asset": { + "type": "string", + "enum": [ + "launch_token", + "quote_token" + ] + } + }, + "required": [ + "event", + "forwarding_locker", + "direction", + "launch_token_delta", + "quote_token_delta", + "fee_rate", + "fee_amount", + "fee_asset" + ], + "additionalProperties": false + } + } + }, + "required": [ + "schema_version", + "chain_id", + "pool_id", + "next_cursor", + "as_of", + "data" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "The request parameters are invalid", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "The requested resource was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "An unexpected server error occurred", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "The indexed head is missing, inconsistent or stale", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/launches/{chainId}/{poolId}": { + "get": { + "tags": [ + "Launches" + ], + "operationId": "get_GetLaunch", + "summary": "Get a supported launch and separate principal/creator ledgers", + "parameters": [ + { + "schema": { + "type": "integer", + "format": "int64" + }, + "required": true, + "name": "chainId", + "in": "path" + }, + { + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^0x[a-fA-F0-9]+$", + "description": "A hexadecimal number" + }, + { + "type": "string", + "pattern": "^\\d+$", + "description": "A decimal number" + } + ], + "title": "Numeric", + "description": "A number represented in hexadecimal or decimal" + }, + "required": true, + "description": "A number represented in hexadecimal or decimal", + "name": "poolId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Indexed zero-seed launch data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "zero-seed-launch-api/v7" + ] + }, + "chain_id": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "pool_id": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "pool_key": { + "type": "object", + "properties": { + "core_address": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "token0": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "token1": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "config": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "fee": { + "type": "string", + "enum": [ + "0" + ] + }, + "tick_spacing": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "extension": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + } + }, + "required": [ + "core_address", + "token0", + "token1", + "config", + "fee", + "tick_spacing", + "extension" + ], + "additionalProperties": false + }, + "token": { + "type": "object", + "properties": { + "address": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "symbol": { + "type": [ + "string", + "null" + ] + }, + "decimals": { + "type": "number", + "enum": [ + 18 + ] + } + }, + "required": [ + "address", + "name", + "symbol", + "decimals" + ], + "additionalProperties": false + }, + "quote_token": { + "type": "object", + "properties": { + "address": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "symbol": { + "type": [ + "string", + "null" + ] + }, + "decimals": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "maximum": 255 + }, + "kind": { + "type": "string", + "enum": [ + "native", + "erc20" + ] + } + }, + "required": [ + "address", + "name", + "symbol", + "decimals", + "kind" + ], + "additionalProperties": false + }, + "launch_token_is_token1": { + "type": "boolean" + }, + "controller": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "creator": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "owner": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "logo_url": { + "type": [ + "string", + "null" + ], + "description": "LaunchCreated.logoUrl exactly as emitted; null when empty or not valid UTF-8. Untrusted: never fetched or rewritten here" + }, + "parameters": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "symbol": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "supply": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "quote_token": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "ask_tick": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "upper_tick": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "trading_start": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$" + }, + "decay_rate_x32": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$" + }, + "initial_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "final_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "salt": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "name", + "symbol", + "supply", + "quote_token", + "ask_tick", + "upper_tick", + "trading_start", + "decay_rate_x32", + "initial_fee", + "final_fee", + "salt" + ], + "additionalProperties": false + }, + "range": { + "type": "object", + "properties": { + "tick_spacing": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "aligned_ask_tick": { + "type": "integer" + }, + "aligned_upper_tick": { + "type": "integer" + }, + "pool_tick_lower": { + "type": "integer" + }, + "pool_tick_upper": { + "type": "integer" + } + }, + "required": [ + "tick_spacing", + "aligned_ask_tick", + "aligned_upper_tick", + "pool_tick_lower", + "pool_tick_upper" + ], + "additionalProperties": false + }, + "supply": { + "type": "object", + "properties": { + "requested": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "installed": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "sink": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "sink_holder": { + "type": "string", + "enum": [ + "0x0000000000000000000000000000000000000000" + ] + } + }, + "required": [ + "requested", + "installed", + "sink", + "sink_holder" + ], + "additionalProperties": false + }, + "trading_start": { + "type": "integer", + "minimum": 0 + }, + "status": { + "type": "string", + "enum": [ + "upcoming", + "trading" + ], + "description": "upcoming while evaluated_at < trading_start, else trading" + }, + "fee_schedule": { + "type": "object", + "properties": { + "trading_start": { + "type": "integer", + "minimum": 0 + }, + "initial_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "final_fee": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "decay_rate_x32": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "decayRateX32: unsigned Q32.32 ticks per second as a canonical decimal uint64; 0 keeps initial_fee" + }, + "half_life_seconds": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "Half-life of the excess over the floor, seconds with 6 decimals (floored); null for rate 0. Display only" + }, + "saturation_elapsed_seconds": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)$", + "description": "floor(381061679028371455 / decay_rate_x32): after this many seconds the fee is exactly final_fee; null for rate 0" + }, + "phase": { + "type": "string", + "enum": [ + "before_trading_start", + "decaying", + "at_floor", + "constant" + ] + }, + "fee_rate": { + "type": "string", + "maxLength": 20, + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64" + }, + "evaluated_at": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "trading_start", + "initial_fee", + "final_fee", + "decay_rate_x32", + "half_life_seconds", + "saturation_elapsed_seconds", + "phase", + "fee_rate", + "evaluated_at" + ], + "additionalProperties": false + }, + "market": { + "type": "object", + "properties": { + "price_tick": { + "type": "integer" + }, + "price_x128": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "market_cap": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "floor(price * totalSupply) in raw quote units; totalSupply includes the sink" + }, + "market_cap_usd": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "market_cap / 10^quote decimals * the indexed quote USD price, rounded to 6 decimals; null when the quote has no indexed price or no known decimals" + }, + "raised": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Quote held by the launch pool (buyers' net input)" + }, + "sold": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "installed - launch tokens left in the pool" + }, + "sold_share": { + "type": "string", + "pattern": "^[01]\\.[0-9]{18}$", + "description": "sold / installed, 18 decimals, floored" + }, + "trade_count": { + "type": "integer", + "minimum": 0, + "description": "LaunchSwapped events of the launch, zero fills included" + }, + "volume": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$", + "description": "Sum of |quote delta| over every LaunchSwapped of the launch, buys and sells, fee-inclusive, in raw quote base units" + }, + "volume_usd": { + "type": [ + "string", + "null" + ], + "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{6}$", + "description": "volume / 10^quote decimals * the indexed quote USD price, rounded to 6 decimals; null exactly when market_cap_usd is" + } + }, + "required": [ + "price_tick", + "price_x128", + "market_cap", + "market_cap_usd", + "raised", + "sold", + "sold_share", + "trade_count", + "volume", + "volume_usd" + ], + "additionalProperties": false + }, + "created": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + }, + "event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + }, + "transaction_index": { + "type": "integer", + "minimum": 0 + }, + "event_index": { + "type": "integer", + "minimum": 0 + }, + "transaction_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + "required": [ + "block_number", + "block_hash", + "block_time", + "event_id", + "transaction_index", + "event_index", + "transaction_hash" + ], + "additionalProperties": false + }, + "as_of": { + "type": "object", + "properties": { + "block_number": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "block_time": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "block_number", + "block_hash", + "block_time" + ], + "additionalProperties": false + }, + "principal": { + "type": "object", + "properties": { + "position_id": { + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "liquidity": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "locked": { + "type": "boolean", + "enum": [ + true + ] + }, + "withdrawable": { + "type": "boolean", + "enum": [ + false + ] + }, + "pool_reserves": { + "type": "object", + "properties": { + "launch_token": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "quote_token": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } + }, + "required": [ + "launch_token", + "quote_token" + ], + "additionalProperties": false + } + }, + "required": [ + "position_id", + "liquidity", + "locked", + "withdrawable", + "pool_reserves" + ], + "additionalProperties": false + }, + "fee_ledger": { + "type": "object", + "properties": { + "holder": { + "type": "string", + "pattern": "^0x[0-9a-f]{40}$" + }, + "launch_token": { + "type": "object", + "properties": { + "accrued": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "claimed": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "unclaimed": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } + }, + "required": [ + "accrued", + "claimed", + "unclaimed" + ], + "additionalProperties": false + }, + "quote_token": { + "type": "object", + "properties": { + "accrued": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "claimed": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + }, + "unclaimed": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } + }, + "required": [ + "accrued", + "claimed", + "unclaimed" + ], + "additionalProperties": false + }, + "swap_count": { + "type": "integer", + "minimum": 0 + }, + "claim_count": { + "type": "integer", + "minimum": 0 + }, + "owner_change_count": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "last_event_id": { + "type": "string", + "pattern": "^(0|-?[1-9][0-9]*)$" + } + }, + "required": [ + "holder", + "launch_token", + "quote_token", + "swap_count", + "claim_count", + "owner_change_count", + "last_event_id" + ], + "additionalProperties": false + } + }, + "required": [ + "schema_version", + "chain_id", + "pool_id", + "pool_key", + "token", + "quote_token", + "launch_token_is_token1", + "controller", + "creator", + "owner", + "logo_url", + "parameters", + "range", + "supply", + "trading_start", + "status", + "fee_schedule", + "market", + "created", + "as_of", + "principal", + "fee_ledger" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "The request parameters are invalid", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "The requested resource was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "An unexpected server error occurred", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "The indexed head is missing, inconsistent or stale", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, "/governance/{chainId}/proposals": { "get": { "tags": [ diff --git a/src/contract/cases/launches.ts b/src/contract/cases/launches.ts new file mode 100644 index 0000000..85df16a --- /dev/null +++ b/src/contract/cases/launches.ts @@ -0,0 +1,220 @@ +import { ContractCase, stubQuery } from "../harness"; +import { LOCAL_INSTANCES } from "../../routes/launches/policy"; + +const NATIVE = "0x0000000000000000000000000000000000000000" as const; +const VERSION = "zero-seed-launch-api/v7" as const; + +const pin = LOCAL_INSTANCES[0]; +const owner = `0x${"2".repeat(40)}`; +const zero = `0x${"0".repeat(64)}`; +const as_of = { block_number: "1", block_hash: zero, block_time: 1000 }; +const summary = { + schema_version: VERSION, + chain_id: "31337", + pool_id: zero, + pool_key: { + core_address: pin.core, + token0: NATIVE, + token1: `0x${"1".repeat(40)}`, + config: zero, + fee: "0" as const, + tick_spacing: 17990, + extension: pin.address, + }, + token: { + address: `0x${"1".repeat(40)}`, + name: "Zero Seed", + symbol: "ZERO", + decimals: 18 as const, + }, + quote_token: { + address: NATIVE, + name: null, + symbol: null, + decimals: 18, + kind: "native" as const, + }, + launch_token_is_token1: true, + controller: pin.periphery, + creator: owner, + owner, + logo_url: null, + parameters: { + name: "0x095a65726f205365656400000000000000000000000000000000000000000000", + symbol: + "0x045a45524f000000000000000000000000000000000000000000000000000000", + supply: "1000000000000000000000000000", + quote_token: NATIVE, + ask_tick: "-13815500", + upper_tick: "-9210300", + trading_start: "1000", + decay_rate_x32: "68913100933", + initial_fee: "9223372036854775808", + final_fee: "55340232221128654", + salt: zero, + }, + range: { + tick_spacing: 17990, + aligned_ask_tick: -13798330, + aligned_upper_tick: -9210880, + pool_tick_lower: 9210880, + pool_tick_upper: 13798330, + }, + supply: { + requested: "1000000000000000000000000000", + installed: "999999999999999999999999508", + sink: "492", + sink_holder: NATIVE, + }, + trading_start: 1000, + status: "trading" as const, + fee_schedule: { + trading_start: 1000, + initial_fee: "9223372036854775808", + final_fee: "55340232221128654", + decay_rate_x32: "68913100933", + half_life_seconds: "86400.000001", + saturation_elapsed_seconds: "5529597", + phase: "decaying" as const, + fee_rate: "9223372036854775808", + evaluated_at: 1000, + }, + market: { + price_tick: -13798330, + price_x128: "340282366920938463463374607431768", + market_cap: "1000000000000000000000", + market_cap_usd: null, + raised: "0", + sold: "0", + sold_share: "0.000000000000000000", + trade_count: 0, + volume: "0", + volume_usd: null, + }, + created: { + ...as_of, + event_id: "-1", + transaction_index: 0, + event_index: 0, + transaction_hash: zero, + }, + as_of, +}; +const ledger = { accrued: "0", claimed: "0", unclaimed: "0" }; +const identity = { + schema_version: VERSION, + chain_id: "31337", + pool_id: zero, + as_of, + next_cursor: null, +}; +const path = `/launches/31337/${zero}`; +export const launchesCases: ContractCase[] = [ + { + operation: "/launches", + request: "/launches?status=trading", + stub: () => + stubQuery("readZeroSeedList", { + schema_version: VERSION, + data: [ + summary, + { + ...summary, + logo_url: "https://example.invalid/logo.svg", + status: "upcoming", + }, + ], + total: 2, + totals: { all: 2, trading: 1, upcoming: 1 }, + aggregates: { + launch_count: 2, + trade_count: 0, + by_quote: [ + { + chain_id: "31337", + quote_token: NATIVE, + launch_count: 2, + trade_count: 0, + volume: "0", + market_cap: "2000000000000000000000", + usd_priced: false, + volume_usd: null, + market_cap_usd: null, + }, + ], + usd: { + volume: null, + market_cap: null, + priced_launch_count: 0, + excluded_launch_count: 2, + }, + }, + next_offset: null, + evaluated_at: 1000, + heads: [{ chain_id: "31337", ...as_of }], + }), + }, + { + operation: "/launches/{chainId}/{poolId}", + request: path, + stub: () => + stubQuery("readZeroSeedDetail", { + ...summary, + principal: { + position_id: zero, + liquidity: "100", + locked: true, + withdrawable: false, + pool_reserves: { launch_token: "1000", quote_token: "0" }, + }, + fee_ledger: { + holder: owner, + launch_token: ledger, + quote_token: ledger, + swap_count: 0, + claim_count: 0, + owner_change_count: 1, + last_event_id: "-1", + }, + }), + }, + { + operation: "/launches/{chainId}/{poolId}/swaps", + request: `${path}/swaps`, + stub: () => stubQuery("readZeroSeedSwaps", { ...identity, data: [] }), + }, + { + operation: "/launches/{chainId}/{poolId}/claims", + request: `${path}/claims`, + stub: () => + stubQuery("readZeroSeedClaims", { + ...identity, + data: [ + { + event: summary.created, + payout_event_id: "1", + owner, + recipient: owner, + launch_token_amount: "0", + quote_token_amount: "5", + }, + ], + totals: { launch_token: "0", quote_token: "5" }, + }), + }, + { + operation: "/launches/{chainId}/{poolId}/owners", + request: `${path}/owners`, + stub: () => + stubQuery("readZeroSeedOwners", { + ...identity, + data: [ + { + event: summary.created, + previous_owner: null, + new_owner: owner, + }, + ], + }), + }, +]; diff --git a/src/queries.ts b/src/queries.ts index ab77b15..774af81 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -1,5 +1,10 @@ import postgres, { type Sql } from "postgres"; import { Env } from "./env"; +import { + LaunchQueries, + type LaunchListOptions, + type LaunchReadOptions, +} from "./routes/launches/queries"; export type StateFilter = "opened" | "closed"; @@ -197,6 +202,26 @@ export class Queries { this.sql = sql; } + public readZeroSeedList(input: LaunchListOptions) { + return new LaunchQueries(this.sql).list(input); + } + + public readZeroSeedDetail(chainId: bigint, poolId: bigint) { + return new LaunchQueries(this.sql).detail(chainId, poolId); + } + + public readZeroSeedSwaps(input: LaunchReadOptions & { poolId: bigint }) { + return new LaunchQueries(this.sql).swaps(input); + } + + public readZeroSeedClaims(input: LaunchReadOptions & { poolId: bigint }) { + return new LaunchQueries(this.sql).claims(input); + } + + public readZeroSeedOwners(input: LaunchReadOptions & { poolId: bigint }) { + return new LaunchQueries(this.sql).owners(input); + } + public async listErc20Tokens({ minVisibilityPriority, pageSize, diff --git a/src/responseSchemas.test.ts b/src/responseSchemas.test.ts index b4477ee..5ff9e9c 100644 --- a/src/responseSchemas.test.ts +++ b/src/responseSchemas.test.ts @@ -18,6 +18,7 @@ import { stateCases } from "./contract/cases/state"; import { statsCases } from "./contract/cases/stats"; import { twammCases } from "./contract/cases/twamm"; import { ve33Cases } from "./contract/cases/ve33"; +import { launchesCases } from "./contract/cases/launches"; const cases: ContractCase[] = [ ...metaCases, @@ -30,6 +31,7 @@ const cases: ContractCase[] = [ ...auctionsCases, ...governanceCases, ...ve33Cases, + ...launchesCases, ...incentivesCases, ]; diff --git a/src/router.test.ts b/src/router.test.ts index 9530b0b..7360f97 100644 --- a/src/router.test.ts +++ b/src/router.test.ts @@ -24,14 +24,14 @@ describe("Hono app integration", () => { ), ); - expect(Object.keys(schema.paths ?? {})).toHaveLength(59); - expect(operations).toHaveLength(59); + expect(Object.keys(schema.paths ?? {})).toHaveLength(64); + expect(operations).toHaveLength(64); expect( operations.reduce( (count, operation) => count + (operation.parameters?.length ?? 0), 0, ), - ).toBe(198); + ).toBe(219); const getToken = operations.find( (operation) => diff --git a/src/router.ts b/src/router.ts index dc57938..4087711 100644 --- a/src/router.ts +++ b/src/router.ts @@ -65,6 +65,13 @@ import { GetAuctionNftState, ListAuctions, } from "./routes/auctions"; +import { + GetLaunch, + ListLaunchClaims, + ListLaunches, + ListLaunchOwners, + ListLaunchSwaps, +} from "./routes/launches"; import { ListVe33Pools, ListVe33TokensByAddress, @@ -123,6 +130,11 @@ const routes: readonly ApiRoute[] = [ GetAuctionNftMetadata, GetAuctionNftState, GetAuctionNftImage, + ListLaunches, + ListLaunchClaims, + ListLaunchOwners, + ListLaunchSwaps, + GetLaunch, ListProposals, ListTopDelegates, ListVotesOnProposal, diff --git a/src/routes/launches/README.md b/src/routes/launches/README.md new file mode 100644 index 0000000..414539b --- /dev/null +++ b/src/routes/launches/README.md @@ -0,0 +1,177 @@ +# Zero-seed launch reads (draft/local) + +Response contract `zero-seed-launch-api/v7`, for the final `ZeroSeedLaunch` +and `ZeroSeedLaunchPeriphery` of the evm-contracts source freeze +`853b608ec26d4c80bdad6e394cb8ba686e1ae615` (compiled ABI file sha256 +`6a131c2d…56eb` and `5d05426f…c839`). It reads the indexer's +`zero_seed_launch_*` tables of migration `00140_zero_seed_launch` (final-only). +No deployment of the final contract exists, so the hosted instance and quote +lists are empty and every launch route answers 404 when hosted. + +## Changes from v6 + +- `market.volume` (sum of |quote delta| over every `LaunchSwapped`, buys and + sells, fee-inclusive, raw quote base units) and `market.volume_usd` + (`volume / 10^decimals * indexed quote price`, 6 decimals, null without a + price or known decimals, exactly when `market_cap_usd` is null). + `market_cap_usd` is now constrained to the same 6-decimal format. +- `order_by` adds `volume`, `sold_share` and `trade_count` to `market_cap` + (default) and `created`. Every order is descending and applied in SQL to + the whole filtered set before `offset`/`limit`; ties are newest first + (`block_time DESC, chain_id, event_id DESC`). `market_cap` and `volume` + rank launches with a USD value first by USD, then the others by whole + quote units (`raw / 10^decimals`; unknown decimals last), as the interface + does. `market_cap` previously put every unpriced launch last in creation + order. +- `aggregates` on the list, over the same set `total` counts (all filters, + status included, never one page): + `{ launch_count, trade_count, by_quote: [{ chain_id, quote_token, + launch_count, trade_count, volume, market_cap, usd_priced, volume_usd, + market_cap_usd }], usd: { volume, market_cap, priced_launch_count, + excluded_launch_count } }`. Raw amounts are summed per (chain, quote + token) only; the USD sums add the served per-launch USD values of priced + launches and are null when none is priced; `excluded_launch_count` counts + launches without a USD value. + +## Changes from v5 + +- Final model only. The fixed-base (`fixed_base_duration_v1`) and earlier + tick-rate drafts, the `fee_schedule.model` discriminator, their pins, + vectors and goldens are removed. There is one fee curve: the shifted + exponential of `decayRateX32` toward the `final_fee` floor. +- New on every launch: `logo_url`, `parameters` (every `LaunchParameters` + field: numbers as exact decimal strings, words as 32-byte hex), `range` + (derived `tick_spacing`, `aligned_ask_tick`, `aligned_upper_tick`, pool + ticks), `trading_start`, `status`, `market`. `token.name`/`symbol` are + decoded from the packed words and `token.decimals` is always 18. + Top-level `ask_tick`/`upper_tick` moved into `parameters` as strings. +- Removed: `inventory` (see `status` and `market`), `principal.tick_*`, + `principal.reserves_basis`, `fee_ledger.transferable`. +- Claims are one row per claim keyed on the extension's `CreatorFeesClaimed` + (`event`), with the periphery `LaunchFeesClaimed` of the same transaction + as `payout_event_id`, `owner` and `recipient`; the page has `totals` + (claimed per asset, from the ledger). `ledger_event_id` is gone. +- The list spans chains (`chainId` optional), filters `status`, `owner` + (current) and `creator` (original), orders by `market_cap` (default) or + `created`, pages by `offset`, and reports `total`, `totals`, + `next_offset`, `evaluated_at` and one head per chain (`heads`). + +## Shapes + +`LaunchSummary` (list item; `LaunchDetail` adds `principal` and `fee_ledger`): + +```text +schema_version "zero-seed-launch-api/v7" +chain_id decimal string +pool_id 0x + 64 hex +pool_key { core_address, token0, token1, config: bytes32, fee: "0", tick_spacing: int, extension } +token { address, name: string|null, symbol: string|null, decimals: 18 } +quote_token { address, name|null, symbol|null, decimals: int|null, kind: "native"|"erc20" } +launch_token_is_token1 bool +controller address (the periphery) +creator address (owner at creation) +owner address (current owner; holds unclaimed and future fees) +logo_url string|null (null when "" or not valid UTF-8; otherwise exactly as emitted) +parameters { name: bytes32, symbol: bytes32, supply, quote_token: address, ask_tick, upper_tick, + trading_start, decay_rate_x32, initial_fee, final_fee: decimal strings, salt: bytes32 } +range { tick_spacing, aligned_ask_tick, aligned_upper_tick, pool_tick_lower, pool_tick_upper: int } +supply { requested, installed, sink: decimal strings, sink_holder: 0x0…0 } +trading_start int (unix seconds) +status "upcoming" (evaluated_at < trading_start) | "trading" +fee_schedule { trading_start: int, initial_fee, final_fee, decay_rate_x32: decimal strings, + half_life_seconds: "s.uuuuuu"|null, saturation_elapsed_seconds: string|null, + phase: before_trading_start|decaying|at_floor|constant, fee_rate: decimal string, + evaluated_at: int } +market { price_tick: int, price_x128, market_cap: decimal strings, market_cap_usd: string|null, + raised, sold: decimal strings, sold_share: "d.dddddddddddddddddd", trade_count: int, + volume: decimal string, volume_usd: "d.dddddd"|null } +created { block_number, block_hash, block_time, event_id, transaction_index, event_index, transaction_hash } +as_of { block_number, block_hash, block_time } (the launch chain's indexed head) +principal { position_id, liquidity, locked: true, withdrawable: false, + pool_reserves: { launch_token, quote_token } } +fee_ledger { holder, launch_token: { accrued, claimed, unclaimed }, quote_token: {…}, + swap_count, claim_count, owner_change_count: int, last_event_id } +``` + +`LaunchList`: `{ schema_version, data: LaunchSummary[], total, totals: { all, +trading, upcoming }, aggregates, next_offset: int|null, evaluated_at: int, +heads: [{ chain_id, block_number, block_hash, block_time }] }`. `total` counts +every filter; `totals` counts the non-status filters by status; `aggregates` +(see Changes from v6) covers the same set as `total`. + +Market: `price_x128` is raw quote per raw launch token times 2^128, floored, +from Core's sqrt ratio; `market_cap = floor(price * totalSupply)` in raw quote +units (the sink is not a burn and is included); `market_cap_usd` uses the +indexed quote price (6 decimals) and is null without one; `raised` is the +quote the pool holds; `sold = installed - launch tokens in the pool`; +`trade_count` counts `LaunchSwapped`, including zero fills; `volume` sums +`|quote delta|` over them (fee-inclusive, raw quote units). + +Status and `fee_rate` are evaluated at the request's wall-clock second +(`evaluated_at`); `as_of`/`heads` are the indexed heads. Fee math: +`fee = final + floor((initial - final) * toFixed(tickToSqrtRatio(-m)) / 2^128)`, +`m = floor(rate * elapsed / 2^32)`, initial before and at the start and for +rate 0, `final` once `elapsed > 381061679028371455 / rate`; checked against the +freeze's fee rows, curve tables, tick steps, saturation seconds and SHA-256 +chains (`policy.test.ts`). + +## Requests + +- `GET /launches?chainId=&status=all|trading|upcoming&owner=&creator=&order_by=market_cap|volume|sold_share|trade_count|created&offset=0&limit=50` +- `GET /launches/{chainId}/{poolId}` +- `GET /launches/{chainId}/{poolId}/swaps?limit=50&after_event_id=…` +- `GET /launches/{chainId}/{poolId}/claims?limit=50&after_event_id=…` +- `GET /launches/{chainId}/{poolId}/owners?limit=50&after_event_id=…` + +Limits are 1–200, offsets 0–100000. Histories are oldest first with signed +decimal event-id cursors. Validation errors are 400 and name the parameter +(`Invalid query: status: …`). Missing/unsupported launches are 404; a missing, +mismatched or stale head of a chain in scope is 503 naming the chain; +malformed indexed rows (non-canonical packed name, inconsistent range or +supply, fee outside uint64, claim without its payout) fail as 500. + +## Supported instances and consistency + +Hosted readers enable no instance and no ERC-20 quote. Only the explicit local +harness may pass the reviewed local manifest (`LOCAL_INSTANCES`, the +indexer fixture's instance, and `LOCAL_QUOTES`, its relocated test ERC-20). +SQL screens chain, extension, periphery controller, Core, ordered pair, zero +fee, spacing and the launch's own quote before ordering and paging. Each read +is one read-only repeatable-read transaction. Responses are `no-store`. +Logos and names are untrusted creator input: they are never fetched, +rewritten or sanitized here; clients must escape them and must not fetch +logo URLs unsafely. + +## Local verification + +`bun run format:check`, `bun run lint`, `bun run typecheck`, `bun test`. +`bun run openapi` regenerates `openapi.json`. + +`replay.postgres.test.ts` populates a disposable loopback Postgres through the +indexer's own migrations, stream grouping, processors and DAO from its local +anvil chain (`tests/fixtures/zero-seed-launch/local-chain.json`, sha256 +pinned in the test) and reads every route through the app: + +```sh +docker run -d --rm --name launch-api-pg -p 127.0.0.1:55491:5432 \ + -e POSTGRES_PASSWORD=postgres postgres:18 +ZERO_SEED_INDEXER_WORKTREE=/path/to/indexer \ +TEST_PG_CONNECTION_STRING=postgres://postgres:postgres@127.0.0.1:55491/postgres \ +bun test src/routes/launches/replay.postgres.test.ts +``` + +It checks after every block each launch's parameters and packed metadata +against the raw `LaunchCreated` log, logo, range, supply, ledger, owner, +creator, controller and `feeAt` against the chain state; claims once per +extension claim (counts and sums equal both the extension and the periphery +logs); owner history and paging; list filters, totals, offsets, market-cap +order, every `order_by` against the interface ranking across offset pages, +aggregates against the served launches for each filter (no price, native +priced, mixed quote decimals, both quotes priced), volume and trade count +against each launch's swaps, and quote screening; a reorg; and that a second straight replay and a +redelivery serve identical bodies. With `LAUNCH_GOLDEN_DIR` set it writes +`zero-seed-launch-api-v7.golden.json`; copy it to `fixtures/` and run +`bun run format`. + +Safe stop is launch support off. No deployment, live database, merge or +release is authorized by this draft. diff --git a/src/routes/launches/fixtures/zero-seed-launch-api-v7.golden.json b/src/routes/launches/fixtures/zero-seed-launch-api-v7.golden.json new file mode 100644 index 0000000..c132980 --- /dev/null +++ b/src/routes/launches/fixtures/zero-seed-launch-api-v7.golden.json @@ -0,0 +1,3386 @@ +{ + "source": { + "indexer_commit": "4a2587e5b733fb4f9f5c4dd185abc66493698749", + "fixture_sha256": "b818cb5a4d939a67bd91a672f394ff32146edb9557cdf597e02ecad04d9a64d6", + "evaluated_at": 2115361000 + }, + "list": { + "schema_version": "zero-seed-launch-api/v7", + "data": [ + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x5d58fbe502d86c8606cbc21129514b9989eb79999066f1139904926fd0994384", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0xdec85268897bdaf4ae3fac868429e05f9bf90659", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c0000000000000000800a939c", + "fee": "0", + "tick_spacing": 693148, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xdec85268897bdaf4ae3fac868429e05f9bf90659", + "name": "Zero Seed l8", + "symbol": "L8", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3800000000000000000000000000000000000000", + "symbol": "0x024c380000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-88722835", + "upper_tick": "88722835", + "trading_start": "1800005200", + "decay_rate_x32": "68913100933", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x114620bab65d343f8f17a1536ca597c5641c5e6cbe4398524e79a406de0df42b" + }, + "range": { + "tick_spacing": 693148, + "aligned_ask_tick": -88029796, + "aligned_upper_tick": 88029796, + "pool_tick_lower": -88029796, + "pool_tick_upper": 88029796 + }, + "supply": { + "requested": "1000000000000000000000000000000", + "installed": "999999999987511320520150058769", + "sink": "12488679479849941231", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800005200, + "status": "trading", + "fee_schedule": { + "trading_start": 1800005200, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -88029796, + "price_x128": "1", + "market_cap": "0", + "market_cap_usd": null, + "raised": "1", + "sold": "100000000000000000000", + "sold_share": "0.000000000100000000", + "trade_count": 1, + "volume": "2", + "volume_usd": null + }, + "created": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135233525", + "transaction_index": 1, + "event_index": 10, + "transaction_hash": "0xb0a431eab9a08a25bb3542b81016c59e96d2c1ce978384640542b18d436e8153" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x4092ccb2f914fc005db61f2f29235260e289a2dd31010bcd2e655a8b874743a0", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x1979be2e532c9712f3c4f5aebbb112b3363d2a69", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080002000", + "fee": "0", + "tick_spacing": 8192, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x1979be2e532c9712f3c4f5aebbb112b3363d2a69", + "name": "Zero Seed l7", + "symbol": "L7", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3700000000000000000000000000000000000000", + "symbol": "0x024c370000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-88080384", + "upper_tick": "-85983232", + "trading_start": "1800005200", + "decay_rate_x32": "68913100933", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x3bb0077653d024b802a78f862b2d959f8be504b7f42df81a445180edd449da4e" + }, + "range": { + "tick_spacing": 8192, + "aligned_ask_tick": -88080384, + "aligned_upper_tick": -85983232, + "pool_tick_lower": -88080384, + "pool_tick_upper": -85983232 + }, + "supply": { + "requested": "1000000000000000000000000000000", + "installed": "999999999991410763432286846442", + "sink": "8589236567713153558", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800005200, + "status": "trading", + "fee_schedule": { + "trading_start": 1800005200, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -88080384, + "price_x128": "1", + "market_cap": "0", + "market_cap_usd": null, + "raised": "1", + "sold": "100000000000000000000", + "sold_share": "0.000000000100000000", + "trade_count": 1, + "volume": "2", + "volume_usd": null + }, + "created": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135299067", + "transaction_index": 0, + "event_index": 4, + "transaction_hash": "0xddc99d9b6de8f631e839ffe8c6cf47600c972b909e9793ac88a6e5b288ca1b1b" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8d332c8ca02dbd982b355bfd93b157abb06c657dab38c91f789c6c1a5927c14d", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0xa5c8be0f39023a470ad73955bd023d52636399e4", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa5c8be0f39023a470ad73955bd023d52636399e4", + "name": null, + "symbol": "L6", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x035aff0000000000000000000000000000000000000000000000000000000000", + "symbol": "0x024c360000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "1", + "initial_fee": "18446744073709551615", + "final_fee": "18446744073709551615", + "salt": "0x87f22775ea9a15cba089cab3a4d0d92b968f5f1280cec686b6126b32bdfa72f8" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "18446744073709551615", + "final_fee": "18446744073709551615", + "decay_rate_x32": "1", + "half_life_seconds": "5954091920683119.788732", + "saturation_elapsed_seconds": "381061679028371455", + "phase": "at_floor", + "fee_rate": "18446744073709551615", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13796564, + "price_x128": "346793678803132136179439976012385", + "market_cap": "1019135025834901745761", + "market_cap_usd": null, + "raised": "1000000000000010192", + "sold": "982091443427442213916824", + "sold_share": "0.000982091443427442", + "trade_count": 2, + "volume": "188010215599247750070272", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494775272", + "transaction_index": 4, + "event_index": 23, + "transaction_hash": "0x8d219e66a3a734e1655a128a681f1f3ac6f5811ee4c1d1924cb8b2fe7a14254c" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8386120fbe81ba3df690a19c0616abc9579e65ac1d038c28854355d67d1548be", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x0000000000000000000000000000000000000000", + "token1": "0xa5b756793d33bbc96a4f36fc574abfa1c1a16344", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa5b756793d33bbc96a4f36fc574abfa1c1a16344", + "name": "Zéro 🚀", + "symbol": "L5", + "decimals": 18 + }, + "quote_token": { + "address": "0x0000000000000000000000000000000000000000", + "name": null, + "symbol": null, + "decimals": 18, + "kind": "native" + }, + "launch_token_is_token1": true, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "logo_url": "ipfs://bafyélogo 🚀", + "parameters": { + "name": "0x0a5ac3a9726f20f09f9a80000000000000000000000000000000000000000000", + "symbol": "0x024c350000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0x0000000000000000000000000000000000000000", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "18446744073709551615", + "initial_fee": "18446744073709551615", + "final_fee": "55340232221128654", + "salt": "0xd0018fa3949db0f7478425347db6277a1a4e81620122b9ef181f47b2ade9574e" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": 9210880, + "pool_tick_upper": 13798330 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "sink": "441", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "18446744073709551615", + "final_fee": "55340232221128654", + "decay_rate_x32": "18446744073709551615", + "half_life_seconds": "0.000322", + "saturation_elapsed_seconds": "0", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13793034, + "price_x128": "348019647004654940455006368355745", + "market_cap": "1022737822572846286160", + "market_cap_usd": null, + "raised": "2999999999999999983", + "sold": "2941080334312777133468723", + "sold_share": "0.002941080334312777", + "trade_count": 5, + "volume": "188012215599247750080450", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494840814", + "transaction_index": 3, + "event_index": 17, + "transaction_hash": "0xce4a04be8c2b72e774db76672444ff684141564fcfc9ea16844b62bc8bfc25e3" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0xfd819e34709dc79b7af4a674ead3a1fe88eb0e22871e57e78edc580425076cad", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x99f831f2f9542301bae6ffa6916a7624d1d75545", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x99f831f2f9542301bae6ffa6916a7624d1d75545", + "name": "Zero Seed l4", + "symbol": "L4", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3400000000000000000000000000000000000000", + "symbol": "0x024c340000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "0", + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "salt": "0x64778ffaf8f1b3afdbfda9ef8a1483b1ae9316267a82c4aa2fa77f3f5c800ab7" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "decay_rate_x32": "0", + "half_life_seconds": null, + "saturation_elapsed_seconds": null, + "phase": "constant", + "fee_rate": "922337203685477580", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13785833, + "price_x128": "350535152092893641763330226765819", + "market_cap": "1030130227624569569284", + "market_cap_usd": null, + "raised": "7092704171850925118", + "sold": "6928409872974093301683354", + "sold_share": "0.006928409872974093", + "trade_count": 4, + "volume": "7118213238681326333", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494906356", + "transaction_index": 2, + "event_index": 11, + "transaction_hash": "0x953e3e4c3901fd7081e1a41e36d189eec944f7424dc1b31b329e5aec8339e31c" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x46f469a9f61648d57a55f79be9216890b8618427c03ebe6ab71ae0557e9b5fb3", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x9e621d5e87e699eaebe56bc54a6ce2fc1d6e8380", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x9e621d5e87e699eaebe56bc54a6ce2fc1d6e8380", + "name": "Zero Seed l2", + "symbol": "L2", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3200000000000000000000000000000000000000", + "symbol": "0x024c320000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001000", + "decay_rate_x32": "68913100933", + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "salt": "0x706d1c2beda46be1cbaa68fe362b46cabc10d357d951c50e9fa8faa1112679d8" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001000, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001000, + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13782455, + "price_x128": "351721170929431300655620967870695", + "market_cap": "1033615623730366669443", + "market_cap_usd": null, + "raised": "9017251531406779206", + "sold": "8793513662736047941471448", + "sold_share": "0.008793513662736047", + "trade_count": 4, + "volume": "9072843717270293902", + "volume_usd": null + }, + "created": { + "block_number": "3", + "block_hash": "0x3d50b3ccba7b4ab3df647ceb94e60b76a6ee464eb63bb44151074c3108b7a8b2", + "block_time": 1800000020, + "event_id": "-9223372023969873915", + "transaction_index": 0, + "event_index": 4, + "transaction_hash": "0x9d7d2a206587b1f14e48d669379d1adc8d06f9c245e973f27fec2d73786720dc" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x411e52638869caa3f0808fb6975961407fead4e4704e639680b634c2ca6ef6b1", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x0000000000000000000000000000000000000000", + "token1": "0xa6a58be5a2606e8f0a5fd28c5cc5cace90aafe44", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa6a58be5a2606e8f0a5fd28c5cc5cace90aafe44", + "name": "Zero Seed l1", + "symbol": "L1", + "decimals": 18 + }, + "quote_token": { + "address": "0x0000000000000000000000000000000000000000", + "name": null, + "symbol": null, + "decimals": 18, + "kind": "native" + }, + "launch_token_is_token1": true, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "logo_url": "https://example.invalid/l1.svg", + "parameters": { + "name": "0x0c5a65726f2053656564206c3100000000000000000000000000000000000000", + "symbol": "0x024c310000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0x0000000000000000000000000000000000000000", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001000", + "decay_rate_x32": "9923486534471", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x4ef3c22030c48a824508eaa92d5871f0ef42a8a80ef512ae3934836eed27ebaf" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": 9210880, + "pool_tick_upper": 13798330 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "sink": "441", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001000, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001000, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "9923486534471", + "half_life_seconds": "600.000000", + "saturation_elapsed_seconds": "38399", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13769998, + "price_x128": "356129566344924627381574169859136", + "market_cap": "1046570733498124860716", + "market_cap_usd": null, + "raised": "16142442253306885264", + "sold": "15644177672570445471331431", + "sold_share": "0.015644177672570445", + "trade_count": 10, + "volume": "26941395364369142601", + "volume_usd": null + }, + "created": { + "block_number": "2", + "block_hash": "0x570fcc84e9f797809ba3e5f9138a969cbac2cbb913ad2d9a2a4881b6965ae3b9", + "block_time": 1800000010, + "event_id": "-9223372028264710138", + "transaction_index": 2, + "event_index": 5, + "transaction_hash": "0x9166164828ca58da84d325963c28bd5cf66ddf894017ca90970c4b3efea7215b" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + } + ], + "total": 7, + "totals": { + "all": 7, + "trading": 7, + "upcoming": 0 + }, + "aggregates": { + "launch_count": 7, + "trade_count": 27, + "by_quote": [ + { + "chain_id": "31337", + "quote_token": "0x0000000000000000000000000000000000000000", + "launch_count": 2, + "trade_count": 15, + "volume": "188039156994612119223051", + "market_cap": "2069308556070971146876", + "usd_priced": false, + "volume_usd": null, + "market_cap_usd": null + }, + { + "chain_id": "31337", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "launch_count": 5, + "trade_count": 12, + "volume": "188026406656203701690511", + "market_cap": "3082880877189837984488", + "usd_priced": false, + "volume_usd": null, + "market_cap_usd": null + } + ], + "usd": { + "volume": null, + "market_cap": null, + "priced_launch_count": 0, + "excluded_launch_count": 7 + } + }, + "next_offset": null, + "evaluated_at": 2115361000, + "heads": [ + { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000, + "chain_id": "31337" + } + ] + }, + "l1": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x411e52638869caa3f0808fb6975961407fead4e4704e639680b634c2ca6ef6b1", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x0000000000000000000000000000000000000000", + "token1": "0xa6a58be5a2606e8f0a5fd28c5cc5cace90aafe44", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa6a58be5a2606e8f0a5fd28c5cc5cace90aafe44", + "name": "Zero Seed l1", + "symbol": "L1", + "decimals": 18 + }, + "quote_token": { + "address": "0x0000000000000000000000000000000000000000", + "name": null, + "symbol": null, + "decimals": 18, + "kind": "native" + }, + "launch_token_is_token1": true, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "logo_url": "https://example.invalid/l1.svg", + "parameters": { + "name": "0x0c5a65726f2053656564206c3100000000000000000000000000000000000000", + "symbol": "0x024c310000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0x0000000000000000000000000000000000000000", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001000", + "decay_rate_x32": "9923486534471", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x4ef3c22030c48a824508eaa92d5871f0ef42a8a80ef512ae3934836eed27ebaf" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": 9210880, + "pool_tick_upper": 13798330 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "sink": "441", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001000, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001000, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "9923486534471", + "half_life_seconds": "600.000000", + "saturation_elapsed_seconds": "38399", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13769998, + "price_x128": "356129566344924627381574169859136", + "market_cap": "1046570733498124860716", + "market_cap_usd": null, + "raised": "16142442253306885264", + "sold": "15644177672570445471331431", + "sold_share": "0.015644177672570445", + "trade_count": 10, + "volume": "26941395364369142601", + "volume_usd": null + }, + "created": { + "block_number": "2", + "block_hash": "0x570fcc84e9f797809ba3e5f9138a969cbac2cbb913ad2d9a2a4881b6965ae3b9", + "block_time": 1800000010, + "event_id": "-9223372028264710138", + "transaction_index": 2, + "event_index": 5, + "transaction_hash": "0x9166164828ca58da84d325963c28bd5cf66ddf894017ca90970c4b3efea7215b" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000008c8c0000d28bba", + "liquidity": "1121810267768648385525007", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "984355822327429554528668128", + "quote_token": "16142442253306885264" + } + }, + "fee_ledger": { + "holder": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "launch_token": { + "accrued": "1451851403496426596373491", + "claimed": "1451851403496426596373491", + "unclaimed": "0" + }, + "quote_token": { + "accrued": "9484447569588169453", + "claimed": "9484447569588169453", + "unclaimed": "0" + }, + "swap_count": 10, + "claim_count": 4, + "owner_change_count": 3, + "last_event_id": "-9223371959545233400" + } + }, + "l1/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x411e52638869caa3f0808fb6975961407fead4e4704e639680b634c2ca6ef6b1", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "5", + "block_hash": "0x29be75ab412bc11d154ff2c50069b7e3cbc1f5b5a4590b2ec8928f32d2b101b2", + "block_time": 1800001000, + "event_id": "-9223372015379939327", + "transaction_index": 0, + "event_index": 0, + "transaction_hash": "0xbf35c3ce1d9dcb32c0e1ad29e91c1b076c9a6557326dca5c60e7c7c03581a98c" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "zero_fill", + "launch_token_delta": "0", + "quote_token_delta": "0", + "fee_rate": "9223372036854775808", + "fee_amount": "0", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "5", + "block_hash": "0x29be75ab412bc11d154ff2c50069b7e3cbc1f5b5a4590b2ec8928f32d2b101b2", + "block_time": 1800001000, + "event_id": "-9223372015379873789", + "transaction_index": 1, + "event_index": 2, + "transaction_hash": "0x84a9f43120ccfeee868b3f4501eb58adc0430988c763bda18d7b5e0ad14f060a" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-491045721713716106855018", + "quote_token_delta": "1000000000000000000", + "fee_rate": "9223372036854775808", + "fee_amount": "491045721713716106855019", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "6", + "block_hash": "0xe0e8ffa78a9a26df9896fce1605238a067be6f8f7a5027755a3a633b6278afbd", + "block_time": 1800001060, + "event_id": "-9223372011084972030", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0x3b163179d42cea5cca890c19e760266fc7d322b23fb6e0519ba65ad0bcb8bfa3" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-10000000000000000000000000", + "quote_token_delta": "19284142593632098659", + "fee_rate": "8609418535131466691", + "fee_amount": "9000247090561359127", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "6", + "block_hash": "0xe0e8ffa78a9a26df9896fce1605238a067be6f8f7a5027755a3a633b6278afbd", + "block_time": 1800001060, + "event_id": "-9223372011084906491", + "transaction_index": 1, + "event_index": 4, + "transaction_hash": "0x22bd5e41d1139149a482dac060b4494aae73aa3d4c0c3c20279b6ef52576ff20" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "sell", + "launch_token_delta": "1000000000000000000000000", + "quote_token_delta": "-552900152304903791", + "fee_rate": "8609418535131466691", + "fee_amount": "483886479171949322", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002495037438", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0x3313823e8938f44020f896287a94d1770b8b6ed238ef41e266426dbb4bc70351" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-1252055731769336718170443", + "quote_token_delta": "2000000000000000000", + "fee_rate": "6463658066361875532", + "fee_amount": "675356926022494550268670", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "11", + "block_hash": "0x788d4382b82ff9647c5fcdbbdc9a2df58f23fb876561fd223e2db5fc1e18f019", + "block_time": 1800001756, + "event_id": "-9223371989610135550", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0x5439c6d78575c90da40b015dfe632cc3e6372af474a9eb5b3b135d87e06df267" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-758833536048878826029642", + "quote_token_delta": "1000000000000000000", + "fee_rate": "3883398005406982927", + "fee_amount": "202347223399575124000988", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "12", + "block_hash": "0xab1e4aacf8998e3270a5ff019a545e6f03e23e2dd56633f2f3fd1816ebd394ad", + "block_time": 1800002800, + "event_id": "-9223371985315168254", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0xfdaf942b6745c37a1d21832a8525a9c453b99573e69a6a094ae1c1f6ac5bf3b4" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-897015291833690654902106", + "quote_token_delta": "1000000000000000000", + "fee_rate": "1201344301085512086", + "fee_amount": "62487632820296849412243", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "13", + "block_hash": "0xf1649bb7ef047768e402763e94305bda221d84b4984fc2774d4dcb68fca3a0c1", + "block_time": 1800004599, + "event_id": "-9223371981020200958", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0xa4d1f861846f4a5a6ee79197b4b2f65d4ff62c87bc72d7d8532d23d29e7f1057" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-947509245325636381702945", + "quote_token_delta": "1000000000000000000", + "fee_rate": "198756374052614459", + "fee_amount": "10320233939317764424278", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "14", + "block_hash": "0xd440f23ba0ca0c61434085221a45e74c1d4fbec9da6c08c68669829d6d61f9f8", + "block_time": 1800004600, + "event_id": "-9223371976725233662", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0xb8c5cdfa979425ec890a09269ce40d7caaeec1caa3ff8a6a73760d7fe2596c3e" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-945866742382760187297786", + "quote_token_delta": "1000000000000000000", + "fee_rate": "198590752489824724", + "fee_amount": "10293665601026201412293", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000, + "event_id": "-9223371959545364478", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0x9fe48e9dcf8c17fea8fe10ac8a9e81126bbf878b284a7663ccfbfcbf8e71721b" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "sell", + "launch_token_delta": "100000000000000000000000", + "quote_token_delta": "-104352618432140151", + "fee_rate": "55340232221128654", + "fee_amount": "313999854861004", + "fee_asset": "quote_token" + } + ] + }, + "l1/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x411e52638869caa3f0808fb6975961407fead4e4704e639680b634c2ca6ef6b1", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "6", + "block_hash": "0xe0e8ffa78a9a26df9896fce1605238a067be6f8f7a5027755a3a633b6278afbd", + "block_time": 1800001060, + "event_id": "-9223372011084775413", + "transaction_index": 3, + "event_index": 10, + "transaction_hash": "0xb24950ad479de42d8e046f303eeab022cc8bdda19b2f4b4ef3c50971179400fd" + }, + "payout_event_id": "-9223372011084775411", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "recipient": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "launch_token_amount": "491045721713716106855019", + "quote_token_amount": "9484133569733308449" + }, + { + "event": { + "block_number": "12", + "block_hash": "0xab1e4aacf8998e3270a5ff019a545e6f03e23e2dd56633f2f3fd1816ebd394ad", + "block_time": 1800002800, + "event_id": "-9223371985315037176", + "transaction_index": 2, + "event_index": 7, + "transaction_hash": "0x44d19cc71cfedf0937bac15b9b7e2b56a1b8ed049ec156cd52d56b2cb69be97c" + }, + "payout_event_id": "-9223371985315037174", + "owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "recipient": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "launch_token_amount": "940191782242366523681901", + "quote_token_amount": "0" + }, + { + "event": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000, + "event_id": "-9223371959545298940", + "transaction_index": 1, + "event_index": 3, + "transaction_hash": "0xacbf491054ae9332743f0f88ea6e6aa278cc588d220e5dc57d1dfcf60fb5d6ab" + }, + "payout_event_id": "-9223371959545298938", + "owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "recipient": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "launch_token_amount": "20613899540343965836571", + "quote_token_amount": "313999854861004" + }, + { + "event": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000, + "event_id": "-9223371959545233401", + "transaction_index": 2, + "event_index": 6, + "transaction_hash": "0xbcde3793eab80cca03ab163e517b25b7bd8bba94336dfefd8073a5d491c244d2" + }, + "payout_event_id": "-9223371959545233400", + "owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "recipient": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "launch_token_amount": "0", + "quote_token_amount": "0" + } + ], + "totals": { + "launch_token": "1451851403496426596373491", + "quote_token": "9484447569588169453" + } + }, + "l1/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x411e52638869caa3f0808fb6975961407fead4e4704e639680b634c2ca6ef6b1", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "2", + "block_hash": "0x570fcc84e9f797809ba3e5f9138a969cbac2cbb913ad2d9a2a4881b6965ae3b9", + "block_time": 1800000010, + "event_id": "-9223372028264710137", + "transaction_index": 2, + "event_index": 6, + "transaction_hash": "0x9166164828ca58da84d325963c28bd5cf66ddf894017ca90970c4b3efea7215b" + }, + "previous_owner": null, + "new_owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8" + }, + { + "event": { + "block_number": "10", + "block_hash": "0xca53b68272a9a116f305f46fbf57bef1cade347bfb86a7fadd3649471cf6a22e", + "block_time": 1800001700, + "event_id": "-9223371993904971767", + "transaction_index": 2, + "event_index": 8, + "transaction_hash": "0xc334b52ed56a9e20678955fc7d4452e106e04d655b83b5cf4c65f81b06a32d9d" + }, + "previous_owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "new_owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906" + }, + { + "event": { + "block_number": "11", + "block_hash": "0x788d4382b82ff9647c5fcdbbdc9a2df58f23fb876561fd223e2db5fc1e18f019", + "block_time": 1800001756, + "event_id": "-9223371989610070012", + "transaction_index": 1, + "event_index": 3, + "transaction_hash": "0xdcd51ca1e16b4a0187fb9fb759d9be4d626b36f192f24b500e4c43443455778f" + }, + "previous_owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "new_owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc" + } + ] + }, + "l2": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x46f469a9f61648d57a55f79be9216890b8618427c03ebe6ab71ae0557e9b5fb3", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x9e621d5e87e699eaebe56bc54a6ce2fc1d6e8380", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x9e621d5e87e699eaebe56bc54a6ce2fc1d6e8380", + "name": "Zero Seed l2", + "symbol": "L2", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3200000000000000000000000000000000000000", + "symbol": "0x024c320000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001000", + "decay_rate_x32": "68913100933", + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "salt": "0x706d1c2beda46be1cbaa68fe362b46cabc10d357d951c50e9fa8faa1112679d8" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001000, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001000, + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13782455, + "price_x128": "351721170929431300655620967870695", + "market_cap": "1033615623730366669443", + "market_cap_usd": null, + "raised": "9017251531406779206", + "sold": "8793513662736047941471448", + "sold_share": "0.008793513662736047", + "trade_count": 4, + "volume": "9072843717270293902", + "volume_usd": null + }, + "created": { + "block_number": "3", + "block_hash": "0x3d50b3ccba7b4ab3df647ceb94e60b76a6ee464eb63bb44151074c3108b7a8b2", + "block_time": 1800000020, + "event_id": "-9223372023969873915", + "transaction_index": 0, + "event_index": 4, + "transaction_hash": "0x9d7d2a206587b1f14e48d669379d1adc8d06f9c245e973f27fec2d73786720dc" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000ff2d7446ff737400", + "liquidity": "1121810267768648385524834", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "991206486337263952058528060", + "quote_token": "9017251531406779206" + } + }, + "fee_ledger": { + "holder": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "launch_token": { + "accrued": "388899155321923602869114", + "claimed": "244160676971611651450703", + "unclaimed": "144738478350311951418411" + }, + "quote_token": { + "accrued": "53592185863514696", + "claimed": "53592185863514696", + "unclaimed": "0" + }, + "swap_count": 4, + "claim_count": 1, + "owner_change_count": 2, + "last_event_id": "-9223371993905037306" + } + }, + "l2/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x46f469a9f61648d57a55f79be9216890b8618427c03ebe6ab71ae0557e9b5fb3", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "5", + "block_hash": "0x29be75ab412bc11d154ff2c50069b7e3cbc1f5b5a4590b2ec8928f32d2b101b2", + "block_time": 1800001000, + "event_id": "-9223372015379808250", + "transaction_index": 2, + "event_index": 5, + "transaction_hash": "0xd35603d3fc9f3cc0185bf6167b06d644139152bca3933792c9ee9e4beaaa04a7" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-1000000000000000000000000", + "quote_token_delta": "1071843717270293902", + "fee_rate": "922337203685477580", + "fee_amount": "53592185863514696", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "6", + "block_hash": "0xe0e8ffa78a9a26df9896fce1605238a067be6f8f7a5027755a3a633b6278afbd", + "block_time": 1800001060, + "event_id": "-9223372011084840952", + "transaction_index": 2, + "event_index": 7, + "transaction_hash": "0xc616880dbb7e4b136ff60831fb48ad93e7a8d823fcca2d2ebbe3eab813873918" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-4640289101439344548241033", + "quote_token_delta": "5000000000000000000", + "fee_rate": "921920278629180106", + "fee_amount": "244109536925548806220012", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "7", + "block_hash": "0x4db4904b50455c80829239f5dcb927952782f5c76c325f3b4473efc5b04a4e67", + "block_time": 1800001120, + "event_id": "-9223372006789939197", + "transaction_index": 1, + "event_index": 2, + "transaction_hash": "0x938369e6e99027852c823cd426402e2d7d631ee4fd7543469aa52bb1b9a3aea1" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "sell", + "launch_token_delta": "1023726691919932397035", + "quote_token_delta": "-1000000000000000", + "fee_rate": "921503120984176012", + "fee_amount": "51140046062845230691", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "10", + "block_hash": "0xca53b68272a9a116f305f46fbf57bef1cade347bfb86a7fadd3649471cf6a22e", + "block_time": 1800001700, + "event_id": "-9223371993905037306", + "transaction_index": 1, + "event_index": 5, + "transaction_hash": "0x373f3322390d772dee9f13e0b6b9e61c1e0efd1a9c6b838679a0eea9dd8e7b6d" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-2765349132666699722758336", + "quote_token_delta": "3000000000000000000", + "fee_rate": "917482228933054387", + "fee_amount": "144738478350311951418411", + "fee_asset": "launch_token" + } + ] + }, + "l2/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x46f469a9f61648d57a55f79be9216890b8618427c03ebe6ab71ae0557e9b5fb3", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494971900", + "transaction_index": 1, + "event_index": 3, + "transaction_hash": "0xf3e28dcc77895f7d14615e7946c262afd537dcfa78e2ed6fafa60b91567b583e" + }, + "payout_event_id": "-9223372002494971897", + "owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "recipient": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "launch_token_amount": "244160676971611651450703", + "quote_token_amount": "53592185863514696" + } + ], + "totals": { + "launch_token": "244160676971611651450703", + "quote_token": "53592185863514696" + } + }, + "l2/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x46f469a9f61648d57a55f79be9216890b8618427c03ebe6ab71ae0557e9b5fb3", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "3", + "block_hash": "0x3d50b3ccba7b4ab3df647ceb94e60b76a6ee464eb63bb44151074c3108b7a8b2", + "block_time": 1800000020, + "event_id": "-9223372023969873914", + "transaction_index": 0, + "event_index": 5, + "transaction_hash": "0x9d7d2a206587b1f14e48d669379d1adc8d06f9c245e973f27fec2d73786720dc" + }, + "previous_owner": null, + "new_owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8" + }, + { + "event": { + "block_number": "7", + "block_hash": "0x4db4904b50455c80829239f5dcb927952782f5c76c325f3b4473efc5b04a4e67", + "block_time": 1800001120, + "event_id": "-9223372006790004735", + "transaction_index": 0, + "event_index": 0, + "transaction_hash": "0x6b1553a70841f6999c6985312e57b1639bb7ea5fe95209d0b29d1fe9a3b63cee" + }, + "previous_owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "new_owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906" + } + ] + }, + "l4": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0xfd819e34709dc79b7af4a674ead3a1fe88eb0e22871e57e78edc580425076cad", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x99f831f2f9542301bae6ffa6916a7624d1d75545", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x99f831f2f9542301bae6ffa6916a7624d1d75545", + "name": "Zero Seed l4", + "symbol": "L4", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3400000000000000000000000000000000000000", + "symbol": "0x024c340000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "0", + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "salt": "0x64778ffaf8f1b3afdbfda9ef8a1483b1ae9316267a82c4aa2fa77f3f5c800ab7" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "decay_rate_x32": "0", + "half_life_seconds": null, + "saturation_elapsed_seconds": null, + "phase": "constant", + "fee_rate": "922337203685477580", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13785833, + "price_x128": "350535152092893641763330226765819", + "market_cap": "1030130227624569569284", + "market_cap_usd": null, + "raised": "7092704171850925118", + "sold": "6928409872974093301683354", + "sold_share": "0.006928409872974093", + "trade_count": 4, + "volume": "7118213238681326333", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494906356", + "transaction_index": 2, + "event_index": 11, + "transaction_hash": "0x953e3e4c3901fd7081e1a41e36d189eec944f7424dc1b31b329e5aec8339e31c" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000ff2d7446ff737400", + "liquidity": "1121810267768648385524834", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "993071590127025906698316154", + "quote_token": "7092704171850925118" + } + }, + "fee_ledger": { + "holder": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "launch_token": { + "accrued": "341920493648704664787599", + "claimed": "341920493648704664787599", + "unclaimed": "0" + }, + "quote_token": { + "accrued": "5936415422760581", + "claimed": "5936415422760581", + "unclaimed": "0" + }, + "swap_count": 4, + "claim_count": 1, + "owner_change_count": 1, + "last_event_id": "-9223371976725168121" + } + }, + "l4/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0xfd819e34709dc79b7af4a674ead3a1fe88eb0e22871e57e78edc580425076cad", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "9", + "block_hash": "0x645b2482c9f83ac034a48b288f1c1325154e9f3fa6635a5f3e3948aa1533ed2e", + "block_time": 1800001400, + "event_id": "-9223371998200004606", + "transaction_index": 1, + "event_index": 1, + "transaction_hash": "0x1a270a5cb7d827d0026e49262e4d819354dded39a477f4c526aeb00a845ac4ff" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "zero_fill", + "launch_token_delta": "0", + "quote_token_delta": "0", + "fee_rate": "922337203685477580", + "fee_amount": "0", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "9", + "block_hash": "0x645b2482c9f83ac034a48b288f1c1325154e9f3fa6635a5f3e3948aa1533ed2e", + "block_time": 1800001400, + "event_id": "-9223371998199939068", + "transaction_index": 2, + "event_index": 3, + "transaction_hash": "0x7d23c2ee3d129457826ad71710ab4108d3b5608ee7b1fc2b010790b7aa59aeb3" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-6496489379325388636895755", + "quote_token_delta": "7000000000000000000", + "fee_rate": "922337203685477580", + "fee_amount": "341920493648704664787599", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "10", + "block_hash": "0xca53b68272a9a116f305f46fbf57bef1cade347bfb86a7fadd3649471cf6a22e", + "block_time": 1800001700, + "event_id": "-9223371993905102846", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0xfb0fd212addcc91010e949b9d9445affdf5041b7a9899a7e3e1921aec77ded8c" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-100000000000000000000000", + "quote_token_delta": "108426912977506016", + "fee_rate": "922337203685477580", + "fee_amount": "5421345648875301", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "12", + "block_hash": "0xab1e4aacf8998e3270a5ff019a545e6f03e23e2dd56633f2f3fd1816ebd394ad", + "block_time": 1800002800, + "event_id": "-9223371985315102715", + "transaction_index": 1, + "event_index": 4, + "transaction_hash": "0xaf474ffefe422c04233218084510d20f77d7d54dd4ee17d6c058dc6c36b2a313" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "sell", + "launch_token_delta": "10000000000000000000000", + "quote_token_delta": "-9786325703820317", + "fee_rate": "922337203685477580", + "fee_amount": "515069773885280", + "fee_asset": "quote_token" + } + ] + }, + "l4/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0xfd819e34709dc79b7af4a674ead3a1fe88eb0e22871e57e78edc580425076cad", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "14", + "block_hash": "0xd440f23ba0ca0c61434085221a45e74c1d4fbec9da6c08c68669829d6d61f9f8", + "block_time": 1800004600, + "event_id": "-9223371976725168124", + "transaction_index": 1, + "event_index": 3, + "transaction_hash": "0x82a2f4ea905b275b9e8ac2c0a899231bb72c5679d92888e06eef2ce0b0d4641b" + }, + "payout_event_id": "-9223371976725168121", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "recipient": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "launch_token_amount": "341920493648704664787599", + "quote_token_amount": "5936415422760581" + } + ], + "totals": { + "launch_token": "341920493648704664787599", + "quote_token": "5936415422760581" + } + }, + "l4/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0xfd819e34709dc79b7af4a674ead3a1fe88eb0e22871e57e78edc580425076cad", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494906355", + "transaction_index": 2, + "event_index": 12, + "transaction_hash": "0x953e3e4c3901fd7081e1a41e36d189eec944f7424dc1b31b329e5aec8339e31c" + }, + "previous_owner": null, + "new_owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" + } + ] + }, + "l5": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8386120fbe81ba3df690a19c0616abc9579e65ac1d038c28854355d67d1548be", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x0000000000000000000000000000000000000000", + "token1": "0xa5b756793d33bbc96a4f36fc574abfa1c1a16344", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa5b756793d33bbc96a4f36fc574abfa1c1a16344", + "name": "Zéro 🚀", + "symbol": "L5", + "decimals": 18 + }, + "quote_token": { + "address": "0x0000000000000000000000000000000000000000", + "name": null, + "symbol": null, + "decimals": 18, + "kind": "native" + }, + "launch_token_is_token1": true, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "logo_url": "ipfs://bafyélogo 🚀", + "parameters": { + "name": "0x0a5ac3a9726f20f09f9a80000000000000000000000000000000000000000000", + "symbol": "0x024c350000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0x0000000000000000000000000000000000000000", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "18446744073709551615", + "initial_fee": "18446744073709551615", + "final_fee": "55340232221128654", + "salt": "0xd0018fa3949db0f7478425347db6277a1a4e81620122b9ef181f47b2ade9574e" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": 9210880, + "pool_tick_upper": 13798330 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "sink": "441", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "18446744073709551615", + "final_fee": "55340232221128654", + "decay_rate_x32": "18446744073709551615", + "half_life_seconds": "0.000322", + "saturation_elapsed_seconds": "0", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13793034, + "price_x128": "348019647004654940455006368355745", + "market_cap": "1022737822572846286160", + "market_cap_usd": null, + "raised": "2999999999999999983", + "sold": "2941080334312777133468723", + "sold_share": "0.002941080334312777", + "trade_count": 5, + "volume": "188012215599247750080450", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494840814", + "transaction_index": 3, + "event_index": 17, + "transaction_hash": "0xce4a04be8c2b72e774db76672444ff684141564fcfc9ea16844b62bc8bfc25e3" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000008c8c0000d28bba", + "liquidity": "1121810267768648385525007", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "997058919665687222866530836", + "quote_token": "2999999999999999983" + } + }, + "fee_ledger": { + "holder": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "launch_token": { + "accrued": "987968410100088248326020", + "claimed": "987968410100088248326020", + "unclaimed": "0" + }, + "quote_token": { + "accrued": "188009215599247750060111", + "claimed": "188009215599247750060111", + "unclaimed": "0" + }, + "swap_count": 5, + "claim_count": 1, + "owner_change_count": 1, + "last_event_id": "-9223371972430135287" + } + }, + "l5/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8386120fbe81ba3df690a19c0616abc9579e65ac1d038c28854355d67d1548be", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "9", + "block_hash": "0x645b2482c9f83ac034a48b288f1c1325154e9f3fa6635a5f3e3948aa1533ed2e", + "block_time": 1800001400, + "event_id": "-9223371998199742454", + "transaction_index": 5, + "event_index": 9, + "transaction_hash": "0xf778751bd389e81580d5381a5b322ce140f1ebb12cfe0a558e79227e13b9223e" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-53239", + "quote_token_delta": "1000000000000000000", + "fee_rate": "18446744073709551615", + "fee_amount": "982091443427432213656798", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "9", + "block_hash": "0x645b2482c9f83ac034a48b288f1c1325154e9f3fa6635a5f3e3948aa1533ed2e", + "block_time": 1800001400, + "event_id": "-9223371998199676915", + "transaction_index": 6, + "event_index": 12, + "transaction_hash": "0xa6f23cf7006ee13f513604f9de7222d400a221bdfec475aaed47f1392a8990b4" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-10000000000", + "quote_token_delta": "188009215599247750070272", + "fee_rate": "18446744073709551615", + "fee_amount": "188009215599247750060080", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "12", + "block_hash": "0xab1e4aacf8998e3270a5ff019a545e6f03e23e2dd56633f2f3fd1816ebd394ad", + "block_time": 1800002800, + "event_id": "-9223371985314971636", + "transaction_index": 3, + "event_index": 11, + "transaction_hash": "0x6d1511a15c2cf5a9c10e43f1f9457608b3c5ebdb6e9166a152247f78804c266b" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-977417508254004529376415", + "quote_token_delta": "1000000000000000000", + "fee_rate": "55340232221128654", + "fee_amount": "2941075752018067746301", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "15", + "block_hash": "0x30fa40e7ca5f3c2bb44f3e4ab5d37bc729665bfd2c113bd44bf5b3bd2c23db71", + "block_time": 1800005000, + "event_id": "-9223371972430266366", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0x049f0728be79d24e94ad0a49b876a3cbc210c06224fabeab319585dee4eba517" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "sell", + "launch_token_delta": "10000000000", + "quote_token_delta": "-10178", + "fee_rate": "55340232221128654", + "fee_amount": "31", + "fee_asset": "quote_token" + }, + { + "event": { + "block_number": "15", + "block_hash": "0x30fa40e7ca5f3c2bb44f3e4ab5d37bc729665bfd2c113bd44bf5b3bd2c23db71", + "block_time": 1800005000, + "event_id": "-9223371972430200827", + "transaction_index": 1, + "event_index": 4, + "transaction_hash": "0x16aff27ba3f402bb6b08377892c2fff3629670e70b3d9057282989bcef35d007" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-975694415958684355713049", + "quote_token_delta": "1000000000000000000", + "fee_rate": "55340232221128654", + "fee_amount": "2935890920637966922921", + "fee_asset": "launch_token" + } + ] + }, + "l5/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8386120fbe81ba3df690a19c0616abc9579e65ac1d038c28854355d67d1548be", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "15", + "block_hash": "0x30fa40e7ca5f3c2bb44f3e4ab5d37bc729665bfd2c113bd44bf5b3bd2c23db71", + "block_time": 1800005000, + "event_id": "-9223371972430135289", + "transaction_index": 2, + "event_index": 6, + "transaction_hash": "0x9dc3cc14ccb7e1faa7040a5653a737b9664a5bd06a4d8b5d8e787c2c821bbd94" + }, + "payout_event_id": "-9223371972430135287", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "recipient": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "launch_token_amount": "987968410100088248326020", + "quote_token_amount": "188009215599247750060111" + } + ], + "totals": { + "launch_token": "987968410100088248326020", + "quote_token": "188009215599247750060111" + } + }, + "l5/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8386120fbe81ba3df690a19c0616abc9579e65ac1d038c28854355d67d1548be", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494840813", + "transaction_index": 3, + "event_index": 18, + "transaction_hash": "0xce4a04be8c2b72e774db76672444ff684141564fcfc9ea16844b62bc8bfc25e3" + }, + "previous_owner": null, + "new_owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8" + } + ] + }, + "l6": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8d332c8ca02dbd982b355bfd93b157abb06c657dab38c91f789c6c1a5927c14d", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0xa5c8be0f39023a470ad73955bd023d52636399e4", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa5c8be0f39023a470ad73955bd023d52636399e4", + "name": null, + "symbol": "L6", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x035aff0000000000000000000000000000000000000000000000000000000000", + "symbol": "0x024c360000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "1", + "initial_fee": "18446744073709551615", + "final_fee": "18446744073709551615", + "salt": "0x87f22775ea9a15cba089cab3a4d0d92b968f5f1280cec686b6126b32bdfa72f8" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "18446744073709551615", + "final_fee": "18446744073709551615", + "decay_rate_x32": "1", + "half_life_seconds": "5954091920683119.788732", + "saturation_elapsed_seconds": "381061679028371455", + "phase": "at_floor", + "fee_rate": "18446744073709551615", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -13796564, + "price_x128": "346793678803132136179439976012385", + "market_cap": "1019135025834901745761", + "market_cap_usd": null, + "raised": "1000000000000010192", + "sold": "982091443427442213916824", + "sold_share": "0.000982091443427442", + "trade_count": 2, + "volume": "188010215599247750070272", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494775272", + "transaction_index": 4, + "event_index": 23, + "transaction_hash": "0x8d219e66a3a734e1655a128a681f1f3ac6f5811ee4c1d1924cb8b2fe7a14254c" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000ff2d7446ff737400", + "liquidity": "1121810267768648385524834", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "999017908556572557786082684", + "quote_token": "1000000000000010192" + } + }, + "fee_ledger": { + "holder": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "launch_token": { + "accrued": "982091443427432213863585", + "claimed": "982091443427432213863585", + "unclaimed": "0" + }, + "quote_token": { + "accrued": "188009215599247750060080", + "claimed": "188009215599247750060080", + "unclaimed": "0" + }, + "swap_count": 2, + "claim_count": 1, + "owner_change_count": 1, + "last_event_id": "-9223371985314906095" + } + }, + "l6/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8d332c8ca02dbd982b355bfd93b157abb06c657dab38c91f789c6c1a5927c14d", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "9", + "block_hash": "0x645b2482c9f83ac034a48b288f1c1325154e9f3fa6635a5f3e3948aa1533ed2e", + "block_time": 1800001400, + "event_id": "-9223371998199611376", + "transaction_index": 7, + "event_index": 15, + "transaction_hash": "0xf9048041ca7112458c58a9414a73121c6b4b2877a27cfbc57b6ab710e14d9b25" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-53239", + "quote_token_delta": "1000000000000000000", + "fee_rate": "18446744073709551615", + "fee_amount": "982091443427432213863585", + "fee_asset": "launch_token" + }, + { + "event": { + "block_number": "9", + "block_hash": "0x645b2482c9f83ac034a48b288f1c1325154e9f3fa6635a5f3e3948aa1533ed2e", + "block_time": 1800001400, + "event_id": "-9223371998199545836", + "transaction_index": 8, + "event_index": 19, + "transaction_hash": "0x7d3e67c4b16ec29c35c1238ec1697f58ca567cd03485bef19a7ed0515f4cfb0b" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-10000000000", + "quote_token_delta": "188009215599247750070272", + "fee_rate": "18446744073709551615", + "fee_amount": "188009215599247750060080", + "fee_asset": "quote_token" + } + ] + }, + "l6/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8d332c8ca02dbd982b355bfd93b157abb06c657dab38c91f789c6c1a5927c14d", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "12", + "block_hash": "0xab1e4aacf8998e3270a5ff019a545e6f03e23e2dd56633f2f3fd1816ebd394ad", + "block_time": 1800002800, + "event_id": "-9223371985314906098", + "transaction_index": 4, + "event_index": 13, + "transaction_hash": "0x272380861fc975c0eeddd59d15f59009fc0dee24fa016408169a89154c5e0a3c" + }, + "payout_event_id": "-9223371985314906095", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "recipient": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "launch_token_amount": "982091443427432213863585", + "quote_token_amount": "188009215599247750060080" + } + ], + "totals": { + "launch_token": "982091443427432213863585", + "quote_token": "188009215599247750060080" + } + }, + "l6/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8d332c8ca02dbd982b355bfd93b157abb06c657dab38c91f789c6c1a5927c14d", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494775271", + "transaction_index": 4, + "event_index": 24, + "transaction_hash": "0x8d219e66a3a734e1655a128a681f1f3ac6f5811ee4c1d1924cb8b2fe7a14254c" + }, + "previous_owner": null, + "new_owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" + } + ] + }, + "l7": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x4092ccb2f914fc005db61f2f29235260e289a2dd31010bcd2e655a8b874743a0", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x1979be2e532c9712f3c4f5aebbb112b3363d2a69", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080002000", + "fee": "0", + "tick_spacing": 8192, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x1979be2e532c9712f3c4f5aebbb112b3363d2a69", + "name": "Zero Seed l7", + "symbol": "L7", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3700000000000000000000000000000000000000", + "symbol": "0x024c370000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-88080384", + "upper_tick": "-85983232", + "trading_start": "1800005200", + "decay_rate_x32": "68913100933", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x3bb0077653d024b802a78f862b2d959f8be504b7f42df81a445180edd449da4e" + }, + "range": { + "tick_spacing": 8192, + "aligned_ask_tick": -88080384, + "aligned_upper_tick": -85983232, + "pool_tick_lower": -88080384, + "pool_tick_upper": -85983232 + }, + "supply": { + "requested": "1000000000000000000000000000000", + "installed": "999999999991410763432286846442", + "sink": "8589236567713153558", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800005200, + "status": "trading", + "fee_schedule": { + "trading_start": 1800005200, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -88080384, + "price_x128": "1", + "market_cap": "0", + "market_cap_usd": null, + "raised": "1", + "sold": "100000000000000000000", + "sold_share": "0.000000000100000000", + "trade_count": 1, + "volume": "2", + "volume_usd": null + }, + "created": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135299067", + "transaction_index": 0, + "event_index": 4, + "transaction_hash": "0xddc99d9b6de8f631e839ffe8c6cf47600c972b909e9793ac88a6e5b288ca1b1b" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000fac00000fae00000", + "liquidity": "115073586432", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "999999999891410763432286846442", + "quote_token": "1" + } + }, + "fee_ledger": { + "holder": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "launch_token": { + "accrued": "0", + "claimed": "0", + "unclaimed": "0" + }, + "quote_token": { + "accrued": "1", + "claimed": "0", + "unclaimed": "1" + }, + "swap_count": 1, + "claim_count": 0, + "owner_change_count": 1, + "last_event_id": "-9223371963840331774" + } + }, + "l7/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x4092ccb2f914fc005db61f2f29235260e289a2dd31010bcd2e655a8b874743a0", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "17", + "block_hash": "0x8f5572aaa27b0d285fff6b77cbaf21dc5e39a2c9e5f6d70e2149a512a7944857", + "block_time": 1800005200, + "event_id": "-9223371963840331774", + "transaction_index": 0, + "event_index": 1, + "transaction_hash": "0x016f254daa714fd812183aceb232e96481a537b0021716745f0e1086faef690b" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-100000000000000000000", + "quote_token_delta": "2", + "fee_rate": "9223372036854775808", + "fee_amount": "1", + "fee_asset": "quote_token" + } + ] + }, + "l7/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x4092ccb2f914fc005db61f2f29235260e289a2dd31010bcd2e655a8b874743a0", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [], + "totals": { + "launch_token": "0", + "quote_token": "0" + } + }, + "l7/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x4092ccb2f914fc005db61f2f29235260e289a2dd31010bcd2e655a8b874743a0", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135299066", + "transaction_index": 0, + "event_index": 5, + "transaction_hash": "0xddc99d9b6de8f631e839ffe8c6cf47600c972b909e9793ac88a6e5b288ca1b1b" + }, + "previous_owner": null, + "new_owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8" + } + ] + }, + "l8": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x5d58fbe502d86c8606cbc21129514b9989eb79999066f1139904926fd0994384", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0xdec85268897bdaf4ae3fac868429e05f9bf90659", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c0000000000000000800a939c", + "fee": "0", + "tick_spacing": 693148, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xdec85268897bdaf4ae3fac868429e05f9bf90659", + "name": "Zero Seed l8", + "symbol": "L8", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3800000000000000000000000000000000000000", + "symbol": "0x024c380000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-88722835", + "upper_tick": "88722835", + "trading_start": "1800005200", + "decay_rate_x32": "68913100933", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x114620bab65d343f8f17a1536ca597c5641c5e6cbe4398524e79a406de0df42b" + }, + "range": { + "tick_spacing": 693148, + "aligned_ask_tick": -88029796, + "aligned_upper_tick": 88029796, + "pool_tick_lower": -88029796, + "pool_tick_upper": 88029796 + }, + "supply": { + "requested": "1000000000000000000000000000000", + "installed": "999999999987511320520150058769", + "sink": "12488679479849941231", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800005200, + "status": "trading", + "fee_schedule": { + "trading_start": 1800005200, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 2115361000 + }, + "market": { + "price_tick": -88029796, + "price_x128": "1", + "market_cap": "0", + "market_cap_usd": null, + "raised": "1", + "sold": "100000000000000000000", + "sold_share": "0.000000000100000000", + "trade_count": 1, + "volume": "2", + "volume_usd": null + }, + "created": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135233525", + "transaction_index": 1, + "event_index": 10, + "transaction_hash": "0xb0a431eab9a08a25bb3542b81016c59e96d2c1ce978384640542b18d436e8153" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "principal": { + "position_id": "0x000000000000000000000000000000000000000000000000fac0c59c053f3a64", + "liquidity": "76662368857", + "locked": true, + "withdrawable": false, + "pool_reserves": { + "launch_token": "999999999887511320520150058769", + "quote_token": "1" + } + }, + "fee_ledger": { + "holder": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "launch_token": { + "accrued": "0", + "claimed": "0", + "unclaimed": "0" + }, + "quote_token": { + "accrued": "1", + "claimed": "0", + "unclaimed": "1" + }, + "swap_count": 1, + "claim_count": 0, + "owner_change_count": 1, + "last_event_id": "-9223371963840266234" + } + }, + "l8/swaps?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x5d58fbe502d86c8606cbc21129514b9989eb79999066f1139904926fd0994384", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "17", + "block_hash": "0x8f5572aaa27b0d285fff6b77cbaf21dc5e39a2c9e5f6d70e2149a512a7944857", + "block_time": 1800005200, + "event_id": "-9223371963840266234", + "transaction_index": 1, + "event_index": 5, + "transaction_hash": "0x695c24f02302bcc35a29cadb6dba02d60b20e0a8e892cfc237d0a54fe7f48d1d" + }, + "forwarding_locker": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "direction": "buy", + "launch_token_delta": "-100000000000000000000", + "quote_token_delta": "2", + "fee_rate": "9223372036854775808", + "fee_amount": "1", + "fee_asset": "quote_token" + } + ] + }, + "l8/claims?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x5d58fbe502d86c8606cbc21129514b9989eb79999066f1139904926fd0994384", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [], + "totals": { + "launch_token": "0", + "quote_token": "0" + } + }, + "l8/owners?limit=200": { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x5d58fbe502d86c8606cbc21129514b9989eb79999066f1139904926fd0994384", + "next_cursor": null, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + }, + "data": [ + { + "event": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135233524", + "transaction_index": 1, + "event_index": 11, + "transaction_hash": "0xb0a431eab9a08a25bb3542b81016c59e96d2c1ce978384640542b18d436e8153" + }, + "previous_owner": null, + "new_owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" + } + ] + }, + "list_by_volume_native_priced": { + "schema_version": "zero-seed-launch-api/v7", + "data": [ + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8386120fbe81ba3df690a19c0616abc9579e65ac1d038c28854355d67d1548be", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x0000000000000000000000000000000000000000", + "token1": "0xa5b756793d33bbc96a4f36fc574abfa1c1a16344", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa5b756793d33bbc96a4f36fc574abfa1c1a16344", + "name": "Zéro 🚀", + "symbol": "L5", + "decimals": 18 + }, + "quote_token": { + "address": "0x0000000000000000000000000000000000000000", + "name": null, + "symbol": null, + "decimals": 18, + "kind": "native" + }, + "launch_token_is_token1": true, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "logo_url": "ipfs://bafyélogo 🚀", + "parameters": { + "name": "0x0a5ac3a9726f20f09f9a80000000000000000000000000000000000000000000", + "symbol": "0x024c350000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0x0000000000000000000000000000000000000000", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "18446744073709551615", + "initial_fee": "18446744073709551615", + "final_fee": "55340232221128654", + "salt": "0xd0018fa3949db0f7478425347db6277a1a4e81620122b9ef181f47b2ade9574e" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": 9210880, + "pool_tick_upper": 13798330 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "sink": "441", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "18446744073709551615", + "final_fee": "55340232221128654", + "decay_rate_x32": "18446744073709551615", + "half_life_seconds": "0.000322", + "saturation_elapsed_seconds": "0", + "phase": "at_floor", + "fee_rate": "55340232221128654", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -13793034, + "price_x128": "348019647004654940455006368355745", + "market_cap": "1022737822572846286160", + "market_cap_usd": "2045475.645146", + "raised": "2999999999999999983", + "sold": "2941080334312777133468723", + "sold_share": "0.002941080334312777", + "trade_count": 5, + "volume": "188012215599247750080450", + "volume_usd": "376024431.198496" + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494840814", + "transaction_index": 3, + "event_index": 17, + "transaction_hash": "0xce4a04be8c2b72e774db76672444ff684141564fcfc9ea16844b62bc8bfc25e3" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x411e52638869caa3f0808fb6975961407fead4e4704e639680b634c2ca6ef6b1", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x0000000000000000000000000000000000000000", + "token1": "0xa6a58be5a2606e8f0a5fd28c5cc5cace90aafe44", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa6a58be5a2606e8f0a5fd28c5cc5cace90aafe44", + "name": "Zero Seed l1", + "symbol": "L1", + "decimals": 18 + }, + "quote_token": { + "address": "0x0000000000000000000000000000000000000000", + "name": null, + "symbol": null, + "decimals": 18, + "kind": "native" + }, + "launch_token_is_token1": true, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "logo_url": "https://example.invalid/l1.svg", + "parameters": { + "name": "0x0c5a65726f2053656564206c3100000000000000000000000000000000000000", + "symbol": "0x024c310000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0x0000000000000000000000000000000000000000", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001000", + "decay_rate_x32": "9923486534471", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x4ef3c22030c48a824508eaa92d5871f0ef42a8a80ef512ae3934836eed27ebaf" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": 9210880, + "pool_tick_upper": 13798330 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "sink": "441", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001000, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001000, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "9923486534471", + "half_life_seconds": "600.000000", + "saturation_elapsed_seconds": "38399", + "phase": "decaying", + "fee_rate": "126965494298918151", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -13769998, + "price_x128": "356129566344924627381574169859136", + "market_cap": "1046570733498124860716", + "market_cap_usd": "2093141.466996", + "raised": "16142442253306885264", + "sold": "15644177672570445471331431", + "sold_share": "0.015644177672570445", + "trade_count": 10, + "volume": "26941395364369142601", + "volume_usd": "53882.790729" + }, + "created": { + "block_number": "2", + "block_hash": "0x570fcc84e9f797809ba3e5f9138a969cbac2cbb913ad2d9a2a4881b6965ae3b9", + "block_time": 1800000010, + "event_id": "-9223372028264710138", + "transaction_index": 2, + "event_index": 5, + "transaction_hash": "0x9166164828ca58da84d325963c28bd5cf66ddf894017ca90970c4b3efea7215b" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x5d58fbe502d86c8606cbc21129514b9989eb79999066f1139904926fd0994384", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0xdec85268897bdaf4ae3fac868429e05f9bf90659", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c0000000000000000800a939c", + "fee": "0", + "tick_spacing": 693148, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xdec85268897bdaf4ae3fac868429e05f9bf90659", + "name": "Zero Seed l8", + "symbol": "L8", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3800000000000000000000000000000000000000", + "symbol": "0x024c380000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-88722835", + "upper_tick": "88722835", + "trading_start": "1800005200", + "decay_rate_x32": "68913100933", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x114620bab65d343f8f17a1536ca597c5641c5e6cbe4398524e79a406de0df42b" + }, + "range": { + "tick_spacing": 693148, + "aligned_ask_tick": -88029796, + "aligned_upper_tick": 88029796, + "pool_tick_lower": -88029796, + "pool_tick_upper": 88029796 + }, + "supply": { + "requested": "1000000000000000000000000000000", + "installed": "999999999987511320520150058769", + "sink": "12488679479849941231", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800005200, + "status": "trading", + "fee_schedule": { + "trading_start": 1800005200, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "decaying", + "fee_rate": "9223372036854775808", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -88029796, + "price_x128": "1", + "market_cap": "0", + "market_cap_usd": null, + "raised": "1", + "sold": "100000000000000000000", + "sold_share": "0.000000000100000000", + "trade_count": 1, + "volume": "2", + "volume_usd": null + }, + "created": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135233525", + "transaction_index": 1, + "event_index": 10, + "transaction_hash": "0xb0a431eab9a08a25bb3542b81016c59e96d2c1ce978384640542b18d436e8153" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x4092ccb2f914fc005db61f2f29235260e289a2dd31010bcd2e655a8b874743a0", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x1979be2e532c9712f3c4f5aebbb112b3363d2a69", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080002000", + "fee": "0", + "tick_spacing": 8192, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x1979be2e532c9712f3c4f5aebbb112b3363d2a69", + "name": "Zero Seed l7", + "symbol": "L7", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3700000000000000000000000000000000000000", + "symbol": "0x024c370000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-88080384", + "upper_tick": "-85983232", + "trading_start": "1800005200", + "decay_rate_x32": "68913100933", + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "salt": "0x3bb0077653d024b802a78f862b2d959f8be504b7f42df81a445180edd449da4e" + }, + "range": { + "tick_spacing": 8192, + "aligned_ask_tick": -88080384, + "aligned_upper_tick": -85983232, + "pool_tick_lower": -88080384, + "pool_tick_upper": -85983232 + }, + "supply": { + "requested": "1000000000000000000000000000000", + "installed": "999999999991410763432286846442", + "sink": "8589236567713153558", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800005200, + "status": "trading", + "fee_schedule": { + "trading_start": 1800005200, + "initial_fee": "9223372036854775808", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "decaying", + "fee_rate": "9223372036854775808", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -88080384, + "price_x128": "1", + "market_cap": "0", + "market_cap_usd": null, + "raised": "1", + "sold": "100000000000000000000", + "sold_share": "0.000000000100000000", + "trade_count": 1, + "volume": "2", + "volume_usd": null + }, + "created": { + "block_number": "16", + "block_hash": "0xb89b0e6f054aa84266808b0849968c584d94470768e9ae7bd047e1c7013955d6", + "block_time": 1800005100, + "event_id": "-9223371968135299067", + "transaction_index": 0, + "event_index": 4, + "transaction_hash": "0xddc99d9b6de8f631e839ffe8c6cf47600c972b909e9793ac88a6e5b288ca1b1b" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x8d332c8ca02dbd982b355bfd93b157abb06c657dab38c91f789c6c1a5927c14d", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0xa5c8be0f39023a470ad73955bd023d52636399e4", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0xa5c8be0f39023a470ad73955bd023d52636399e4", + "name": null, + "symbol": "L6", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x035aff0000000000000000000000000000000000000000000000000000000000", + "symbol": "0x024c360000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "1", + "initial_fee": "18446744073709551615", + "final_fee": "18446744073709551615", + "salt": "0x87f22775ea9a15cba089cab3a4d0d92b968f5f1280cec686b6126b32bdfa72f8" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "18446744073709551615", + "final_fee": "18446744073709551615", + "decay_rate_x32": "1", + "half_life_seconds": "5954091920683119.788732", + "saturation_elapsed_seconds": "381061679028371455", + "phase": "at_floor", + "fee_rate": "18446744073709551615", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -13796564, + "price_x128": "346793678803132136179439976012385", + "market_cap": "1019135025834901745761", + "market_cap_usd": null, + "raised": "1000000000000010192", + "sold": "982091443427442213916824", + "sold_share": "0.000982091443427442", + "trade_count": 2, + "volume": "188010215599247750070272", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494775272", + "transaction_index": 4, + "event_index": 23, + "transaction_hash": "0x8d219e66a3a734e1655a128a681f1f3ac6f5811ee4c1d1924cb8b2fe7a14254c" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0xfd819e34709dc79b7af4a674ead3a1fe88eb0e22871e57e78edc580425076cad", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x99f831f2f9542301bae6ffa6916a7624d1d75545", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x99f831f2f9542301bae6ffa6916a7624d1d75545", + "name": "Zero Seed l4", + "symbol": "L4", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3400000000000000000000000000000000000000", + "symbol": "0x024c340000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001400", + "decay_rate_x32": "0", + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "salt": "0x64778ffaf8f1b3afdbfda9ef8a1483b1ae9316267a82c4aa2fa77f3f5c800ab7" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001400, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001400, + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "decay_rate_x32": "0", + "half_life_seconds": null, + "saturation_elapsed_seconds": null, + "phase": "constant", + "fee_rate": "922337203685477580", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -13785833, + "price_x128": "350535152092893641763330226765819", + "market_cap": "1030130227624569569284", + "market_cap_usd": null, + "raised": "7092704171850925118", + "sold": "6928409872974093301683354", + "sold_share": "0.006928409872974093", + "trade_count": 4, + "volume": "7118213238681326333", + "volume_usd": null + }, + "created": { + "block_number": "8", + "block_hash": "0x33c435c8135e24ee87180569416cba7a868940e77ba3cbfdacd7e45e933c17f0", + "block_time": 1800001310, + "event_id": "-9223372002494906356", + "transaction_index": 2, + "event_index": 11, + "transaction_hash": "0x953e3e4c3901fd7081e1a41e36d189eec944f7424dc1b31b329e5aec8339e31c" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + }, + { + "schema_version": "zero-seed-launch-api/v7", + "chain_id": "31337", + "pool_id": "0x46f469a9f61648d57a55f79be9216890b8618427c03ebe6ab71ae0557e9b5fb3", + "pool_key": { + "core_address": "0x00000000000014aa86c5d3c41765bb24e11bd701", + "token0": "0x9e621d5e87e699eaebe56bc54a6ce2fc1d6e8380", + "token1": "0xffffffffffffffffffffffffffffffffffffffff", + "config": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c000000000000000080004646", + "fee": "0", + "tick_spacing": 17990, + "extension": "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c" + }, + "token": { + "address": "0x9e621d5e87e699eaebe56bc54a6ce2fc1d6e8380", + "name": "Zero Seed l2", + "symbol": "L2", + "decimals": 18 + }, + "quote_token": { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "name": null, + "symbol": null, + "decimals": null, + "kind": "erc20" + }, + "launch_token_is_token1": false, + "controller": "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + "creator": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "owner": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "logo_url": null, + "parameters": { + "name": "0x0c5a65726f2053656564206c3200000000000000000000000000000000000000", + "symbol": "0x024c320000000000000000000000000000000000000000000000000000000000", + "supply": "1000000000000000000000000000", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "ask_tick": "-13815500", + "upper_tick": "-9210300", + "trading_start": "1800001000", + "decay_rate_x32": "68913100933", + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "salt": "0x706d1c2beda46be1cbaa68fe362b46cabc10d357d951c50e9fa8faa1112679d8" + }, + "range": { + "tick_spacing": 17990, + "aligned_ask_tick": -13798330, + "aligned_upper_tick": -9210880, + "pool_tick_lower": -13798330, + "pool_tick_upper": -9210880 + }, + "supply": { + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "sink": "492", + "sink_holder": "0x0000000000000000000000000000000000000000" + }, + "trading_start": 1800001000, + "status": "trading", + "fee_schedule": { + "trading_start": 1800001000, + "initial_fee": "922337203685477580", + "final_fee": "55340232221128654", + "decay_rate_x32": "68913100933", + "half_life_seconds": "86400.000001", + "saturation_elapsed_seconds": "5529597", + "phase": "decaying", + "fee_rate": "893610866128455423", + "evaluated_at": 1800005200 + }, + "market": { + "price_tick": -13782455, + "price_x128": "351721170929431300655620967870695", + "market_cap": "1033615623730366669443", + "market_cap_usd": null, + "raised": "9017251531406779206", + "sold": "8793513662736047941471448", + "sold_share": "0.008793513662736047", + "trade_count": 4, + "volume": "9072843717270293902", + "volume_usd": null + }, + "created": { + "block_number": "3", + "block_hash": "0x3d50b3ccba7b4ab3df647ceb94e60b76a6ee464eb63bb44151074c3108b7a8b2", + "block_time": 1800000020, + "event_id": "-9223372023969873915", + "transaction_index": 0, + "event_index": 4, + "transaction_hash": "0x9d7d2a206587b1f14e48d669379d1adc8d06f9c245e973f27fec2d73786720dc" + }, + "as_of": { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000 + } + } + ], + "total": 7, + "totals": { + "all": 7, + "trading": 7, + "upcoming": 0 + }, + "aggregates": { + "launch_count": 7, + "trade_count": 27, + "by_quote": [ + { + "chain_id": "31337", + "quote_token": "0x0000000000000000000000000000000000000000", + "launch_count": 2, + "trade_count": 15, + "volume": "188039156994612119223051", + "market_cap": "2069308556070971146876", + "usd_priced": true, + "volume_usd": "376078313.989225", + "market_cap_usd": "4138617.112142" + }, + { + "chain_id": "31337", + "quote_token": "0xffffffffffffffffffffffffffffffffffffffff", + "launch_count": 5, + "trade_count": 12, + "volume": "188026406656203701690511", + "market_cap": "3082880877189837984488", + "usd_priced": false, + "volume_usd": null, + "market_cap_usd": null + } + ], + "usd": { + "volume": "376078313.989225", + "market_cap": "4138617.112142", + "priced_launch_count": 2, + "excluded_launch_count": 5 + } + }, + "next_offset": null, + "evaluated_at": 1800005200, + "heads": [ + { + "block_number": "18", + "block_hash": "0x41f1936846fcb71cee30f7dd9070915b4fc7dff73f4e94cea11e54c0166606ba", + "block_time": 2115361000, + "chain_id": "31337" + } + ] + } +} diff --git a/src/routes/launches/golden.test.ts b/src/routes/launches/golden.test.ts new file mode 100644 index 0000000..7b2a286 --- /dev/null +++ b/src/routes/launches/golden.test.ts @@ -0,0 +1,81 @@ +import { expect, test } from "bun:test"; +import golden from "./fixtures/zero-seed-launch-api-v7.golden.json"; +import { + ClaimPage, + LaunchDetail, + LaunchList, + OwnerPage, + SCHEMA_VERSION, + SwapPage, +} from "./schema"; + +// Written by replay.postgres.test.ts (LAUNCH_GOLDEN_DIR) from the actual +// handlers over the indexer's replayed local chain: a machine-readable +// example of every v7 response for integrators. +const responses = golden as unknown as Record; + +test("every golden response parses with the closed v7 schemas", () => { + LaunchList.parse(golden.list); + LaunchList.parse(golden.list_by_volume_native_priced); + expect(golden.list.data.length).toBe(7); + for (const [key, body] of Object.entries(responses)) { + if (key === "source" || key.startsWith("list")) continue; + const schema = key.endsWith("/swaps?limit=200") + ? SwapPage + : key.endsWith("/claims?limit=200") + ? ClaimPage + : key.endsWith("/owners?limit=200") + ? OwnerPage + : LaunchDetail; + const parsed = schema.parse(body) as { schema_version: string }; + expect(parsed.schema_version).toBe(SCHEMA_VERSION); + } +}); + +test("golden: logos, statuses and claims as served", () => { + expect(golden.l1.logo_url).toBe("https://example.invalid/l1.svg"); + expect(golden.l2.logo_url).toBeNull(); + expect(golden.l4.logo_url).toBeNull(); + expect(golden.l1.creator).not.toBe(golden.l1.owner); + expect(golden.l1.fee_schedule.evaluated_at).toBe(golden.l1.as_of.block_time); + for (const label of ["l1", "l2", "l4", "l5", "l6"] as const) { + const detail = golden[label]; + const claims = responses[`${label}/claims?limit=200`] as { + data: unknown[]; + totals: unknown; + }; + expect(claims.data.length).toBe(detail.fee_ledger.claim_count); + expect(claims.totals).toEqual({ + launch_token: detail.fee_ledger.launch_token.claimed, + quote_token: detail.fee_ledger.quote_token.claimed, + }); + } +}); + +test("golden: list aggregates never add different quote tokens", () => { + for (const list of [golden.list, golden.list_by_volume_native_priced]) { + const { aggregates } = list; + expect(aggregates.launch_count).toBe(list.total); + expect(aggregates.by_quote.map((g) => g.quote_token)).toEqual([ + "0x0000000000000000000000000000000000000000", + "0xffffffffffffffffffffffffffffffffffffffff", + ]); + for (const group of aggregates.by_quote) { + const launches = list.data.filter( + (l) => l.quote_token.address === group.quote_token, + ); + expect(group.volume).toBe( + launches.reduce((n, l) => n + BigInt(l.market.volume), 0n).toString(), + ); + } + } + // native priced, the ERC-20 not: USD covers the native launches only + const priced = LaunchList.parse( + golden.list_by_volume_native_priced, + ).aggregates; + expect(priced.usd.volume).toBe(priced.by_quote[0].volume_usd); + expect(priced.usd.excluded_launch_count).toBe( + priced.by_quote[1].launch_count, + ); + expect(golden.list.aggregates.usd.volume).toBeNull(); +}); diff --git a/src/routes/launches/index.ts b/src/routes/launches/index.ts new file mode 100644 index 0000000..cf3235a --- /dev/null +++ b/src/routes/launches/index.ts @@ -0,0 +1,226 @@ +import { createRoute, z } from "@hono/zod-openapi"; +import { createQueries } from "../../queries"; +import type { Env } from "../../env"; +import { defineRoute } from "../../shared/context"; +import { + errorResponses, + notFoundResponse, + ErrorResponseType, + StatusError, +} from "../../shared/errors"; +import { + LaunchList, + LaunchDetail, + SwapPage, + ClaimPage, + OwnerPage, +} from "./schema"; +import { + AddressType, + NumericStringType, +} from "../../shared/validation/address"; + +const chainId = z.coerce + .bigint() + .min(0n) + .max((1n << 63n) - 1n) + .openapi({ type: "integer", format: "int64" }); +// Path segments are folded as integers in the edge cache key, so the pool id +// accepts any hex or decimal form of the same uint256. +const poolId = NumericStringType.refine( + (value) => BigInt(value) < 1n << 256n, + "Pool ID out of range", +); +const cursor = z + .string() + .regex(/^(0|-?[1-9][0-9]*)$/) + .transform(BigInt) + .pipe( + z + .bigint() + .min(-(1n << 63n)) + .max((1n << 63n) - 1n), + ) + .openapi({ type: "string" }); +// Numeric like every address query parameter, so the edge cache key folds it. +const address = AddressType.refine( + (value) => BigInt(value) < 1n << 160n, + "Address out of range", +); +const limit = z.coerce.number().int().min(1).max(200).default(50); +const params = z.object({ chainId, poolId }); +const page = z.object({ after_event_id: cursor.optional(), limit }); +const errors = { + ...errorResponses, + ...notFoundResponse, + 503: { + description: "The indexed head is missing, inconsistent or stale", + content: { "application/json": { schema: ErrorResponseType } }, + }, +}; +const response = (schema: z.ZodType) => ({ + description: "Indexed zero-seed launch data", + content: { "application/json": { schema } }, +}); +const headers = { "cache-control": "no-store" }; +function launchQueries(env: Env) { + if (!env.PG_CONNECTION_STRING && !env.HYPERDRIVE) { + throw new StatusError(404, "Launch support is disabled"); + } + return createQueries(env); +} + +export const ListLaunches = defineRoute( + createRoute({ + method: "get", + path: "/launches", + tags: ["Launches"], + operationId: "get_ListLaunches", + summary: + "List supported zero-seed launches across chains, with status, owner and creator filters, ordering and market aggregates", + request: { + query: z.object({ + // omitted: every chain with launch support + chainId: chainId.optional(), + status: z.enum(["all", "trading", "upcoming"]).default("all"), + // current owner + owner: address.optional(), + // owner at creation + creator: address.optional(), + order_by: z + .enum([ + "market_cap", + "volume", + "sold_share", + "trade_count", + "created", + ]) + .default("market_cap") + .openapi({ + description: + "Descending, over every launch matching the filters before offset and limit; ties newest first. market_cap and volume rank launches with a USD value first, by USD, then the rest by whole quote units (raw / 10^decimals); created is newest first", + }), + offset: z.coerce.number().int().min(0).max(100_000).default(0), + limit, + }), + }, + responses: { 200: response(LaunchList), ...errors }, + }), + async (c) => { + const query = c.req.valid("query"); + const q = await launchQueries(c.env); + const data = await q.readZeroSeedList({ + chainId: query.chainId, + status: query.status, + orderBy: query.order_by, + offset: query.offset, + limit: query.limit, + creator: query.creator === undefined ? undefined : BigInt(query.creator), + owner: query.owner === undefined ? undefined : BigInt(query.owner), + }); + return c.json(data, 200, headers); + }, +); + +export const GetLaunch = defineRoute( + createRoute({ + method: "get", + path: "/launches/{chainId}/{poolId}", + tags: ["Launches"], + operationId: "get_GetLaunch", + summary: "Get a supported launch and separate principal/creator ledgers", + request: { params }, + responses: { 200: response(LaunchDetail), ...errors }, + }), + async (c) => { + const { chainId, poolId } = c.req.valid("param"); + const q = await launchQueries(c.env); + return c.json( + await q.readZeroSeedDetail(chainId, BigInt(poolId)), + 200, + headers, + ); + }, +); + +export const ListLaunchSwaps = defineRoute( + createRoute({ + method: "get", + path: "/launches/{chainId}/{poolId}/swaps", + tags: ["Launches"], + operationId: "get_ListLaunchSwaps", + summary: "List swaps; forwarding lockers are contracts, not users", + request: { params, query: page }, + responses: { 200: response(SwapPage), ...errors }, + }), + async (c) => { + const { chainId, poolId } = c.req.valid("param"); + const { after_event_id, limit } = c.req.valid("query"); + const q = await launchQueries(c.env); + return c.json( + await q.readZeroSeedSwaps({ + chainId, + poolId: BigInt(poolId), + cursor: after_event_id, + limit, + }), + 200, + headers, + ); + }, +); + +export const ListLaunchClaims = defineRoute( + createRoute({ + method: "get", + path: "/launches/{chainId}/{poolId}/claims", + tags: ["Launches"], + operationId: "get_ListLaunchClaims", + summary: + "List creator fee claims, one row per claim (extension event, periphery owner and recipient)", + request: { params, query: page }, + responses: { 200: response(ClaimPage), ...errors }, + }), + async (c) => { + const { chainId, poolId } = c.req.valid("param"); + const { after_event_id, limit } = c.req.valid("query"); + const q = await launchQueries(c.env); + return c.json( + await q.readZeroSeedClaims({ + chainId, + poolId: BigInt(poolId), + cursor: after_event_id, + limit, + }), + 200, + headers, + ); + }, +); + +export const ListLaunchOwners = defineRoute( + createRoute({ + method: "get", + path: "/launches/{chainId}/{poolId}/owners", + tags: ["Launches"], + operationId: "get_ListLaunchOwners", + summary: "List the creation owner and every later ownership transfer", + request: { params, query: page }, + responses: { 200: response(OwnerPage), ...errors }, + }), + async (c) => { + const { chainId, poolId } = c.req.valid("param"); + const { after_event_id, limit } = c.req.valid("query"); + const q = await launchQueries(c.env); + return c.json( + await q.readZeroSeedOwners({ + chainId, + poolId: BigInt(poolId), + cursor: after_event_id, + limit, + }), + 200, + headers, + ); + }, +); diff --git a/src/routes/launches/policy.test.ts b/src/routes/launches/policy.test.ts new file mode 100644 index 0000000..b673147 --- /dev/null +++ b/src/routes/launches/policy.test.ts @@ -0,0 +1,473 @@ +import { expect, test } from "bun:test"; +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { + alignedRange, + decayRateForHalfLife, + feeAt, + feeSchedule, + halfLifeSeconds, + HALF_LIFE_X32_E30, + launchStatus, + launchSupply, + LOCAL_INSTANCES, + LOCAL_QUOTES, + marketData, + MAX_DECAY_PRODUCT, + priceX128, + share18, + supportedInstances, + supportedQuote, + supportedQuotes, + tickFactorQ128, + unpackString, + utf8OrNull, +} from "./policy"; +import { FeeSchedule, LaunchDetail, LaunchList, LaunchSummary } from "./schema"; + +const NATIVE = "0x0000000000000000000000000000000000000000"; +const MAX = (1n << 64n) - 1n; +const vectors = resolve(import.meta.dir, "vectors"); +const read = (name: string) => readFileSync(resolve(vectors, name)); +const V = JSON.parse(read("zero-seed-launch.json").toString("utf8")); +const INSTALL = JSON.parse( + read("zero-seed-launch-installation.json").toString("utf8"), +); + +test("vendored vectors are the freeze's bytes", () => { + const sha = (name: string) => + createHash("sha256").update(read(name)).digest("hex"); + expect(sha("zero-seed-launch.json")).toBe( + "e5444bf6b1f7e422238331b50b64cf0400597bd13421e281615735511274190b", + ); + expect(sha("zero-seed-launch-installation.json")).toBe( + "5cf44854cbf00abb700936b2e22782c27dac5e68cf892edc8f5aa7090067a555", + ); + expect(sha("zero-seed-launch-events.json")).toBe( + "24dd5883ce242ec523517c9f38cfd5e8ca29740974aeded5740ac3608e1e7066", + ); + expect(V.version).toBe(8); +}); + +test("local instance manifests bind every field, carry no quote and are refused when hosted", () => { + expect(supportedInstances(LOCAL_INSTANCES, true)).toEqual(LOCAL_INSTANCES); + expect(supportedInstances(LOCAL_INSTANCES, false)).toEqual([]); + expect(supportedInstances([], true)).toEqual([]); + for (const pin of LOCAL_INSTANCES) { + expect(Object.keys(pin).some((key) => /quote|model/i.test(key))).toBe( + false, + ); + for (const key of Object.keys(pin) as (keyof typeof pin)[]) + expect( + supportedInstances([{ ...pin, [key]: "unreviewed" }], true), + ).toEqual([]); + } +}); + +test("quote support is per launch: native, or a reviewed ERC-20 by chain/address/runtime", () => { + const [token] = LOCAL_QUOTES; + expect(supportedQuotes(LOCAL_QUOTES, true)).toEqual(LOCAL_QUOTES); + expect(supportedQuotes(LOCAL_QUOTES, false)).toEqual([]); + for (const key of Object.keys(token) as (keyof typeof token)[]) + expect(supportedQuotes([{ ...token, [key]: "unreviewed" }], true)).toEqual( + [], + ); + const row = { chainId: token.chainId, quote: token.address }; + expect(supportedQuote({ ...row, quoteKind: "erc20" }, LOCAL_QUOTES)).toBe( + true, + ); + expect(supportedQuote({ ...row, quoteKind: "erc20" }, [])).toBe(false); + expect( + supportedQuote({ ...row, chainId: "1", quoteKind: "erc20" }, LOCAL_QUOTES), + ).toBe(false); + expect(supportedQuote({ ...row, quoteKind: "native" }, LOCAL_QUOTES)).toBe( + false, + ); + expect( + supportedQuote({ ...row, quote: NATIVE, quoteKind: "native" }, []), + ).toBe(true); + expect( + supportedQuote({ ...row, quote: NATIVE, quoteKind: "erc20" }, [ + { ...token, address: NATIVE }, + ]), + ).toBe(false); +}); + +test("supply: 0 < installed <= requested <= 10^30 and sink = requested - installed", () => { + const [first] = INSTALL.vectors; + const requested = BigInt(first.supply); + expect( + launchSupply({ + requested, + installed: BigInt(first.installedSupply), + sink: BigInt(first.sink), + }), + ).toEqual({ + requested: first.supply, + installed: first.installedSupply, + sink: first.sink, + sink_holder: NATIVE, + }); + for (const v of INSTALL.vectors) + if (v.installedSupply !== undefined && v.sink !== undefined) + expect( + launchSupply({ + requested: BigInt(v.supply), + installed: BigInt(v.installedSupply), + sink: BigInt(v.sink), + }).sink, + ).toBe(v.sink); + const cap = 10n ** 30n; + expect(launchSupply({ requested: cap, installed: cap, sink: 0n }).sink).toBe( + "0", + ); + for (const bad of [ + { requested, installed: 0n, sink: requested }, + { requested, installed: requested + 1n, sink: -1n }, + { requested, installed: requested - 492n, sink: 491n }, + { requested: cap + 1n, installed: cap + 1n, sink: 0n }, + ]) + expect(() => launchSupply(bad)).toThrow(/Invalid indexed launch supply/); +}); + +test("spacing and signed alignment reproduce every frozen installation vector", () => { + expect(INSTALL.vectors.length).toBe(64); + // eight vectors are tick refusals and have no geometry + const geometric = INSTALL.vectors.filter( + (v: { tickSpacing?: number }) => v.tickSpacing !== undefined, + ); + expect(geometric.length).toBe(56); + for (const v of geometric) { + const range = alignedRange(v.askTick, v.upperTick); + expect(range).toEqual({ + tick_spacing: v.tickSpacing, + aligned_ask_tick: v.alignedAskTick, + aligned_upper_tick: v.alignedUpperTick, + }); + const [lower, upper] = + v.order === "t1" + ? [-range.aligned_upper_tick, -range.aligned_ask_tick] + : [range.aligned_ask_tick, range.aligned_upper_tick]; + expect([lower, upper]).toEqual([v.tickLower, v.tickUpper]); + } + // the spec's table, including no snapping to 1024 + expect(alignedRange(-13815500, -9210300)).toEqual({ + tick_spacing: 17990, + aligned_ask_tick: -13798330, + aligned_upper_tick: -9210880, + }); + expect(alignedRange(-5000001, 4999999)).toEqual({ + tick_spacing: 39063, + aligned_ask_tick: -4961001, + aligned_upper_tick: 4961001, + }); + expect(alignedRange(-88722835, 88722835).tick_spacing).toBe(693148); + expect(() => alignedRange(5, 5)).toThrow(); +}); + +test("names and symbols decode from canonical packOne words; non-canonical words are refused", () => { + const { examples } = V.metadata; + expect(unpackString(BigInt(examples["Zero Seed"]))).toBe("Zero Seed"); + expect(unpackString(BigInt(examples.ZERO))).toBe("ZERO"); + const pack = (bytes: number[]) => + BigInt( + `0x${[bytes.length, ...bytes] + .map((b) => b.toString(16).padStart(2, "0")) + .join("") + .padEnd(64, "0")}`, + ); + // multi-byte UTF-8, a NUL byte and 31 bytes round-trip; invalid UTF-8 is null + expect(unpackString(pack([...new TextEncoder().encode("Zéro 🚀")]))).toBe( + "Zéro 🚀", + ); + expect(unpackString(pack([0x41, 0x00, 0x42]))).toBe("A\u0000B"); + expect(unpackString(pack(Array(31).fill(0x61)))).toBe("a".repeat(31)); + expect(unpackString(pack([0xff, 0xfe]))).toBeNull(); + for (const bad of [ + 0n, + 32n << 248n, + pack([0x41]) | 1n, + (1n << 248n) | (0x41n << 240n) | (0x42n << 232n), + ]) + expect(() => unpackString(bad)).toThrow(/packed/); +}); + +test("logos: empty and invalid UTF-8 are null, everything else is served byte for byte", () => { + const events = JSON.parse( + read("zero-seed-launch-events.json").toString("utf8"), + ); + const logos = events.LaunchCreated.map((e: { logo: string }) => e.logo); + expect(logos).toEqual(["", "https://example.invalid/logo.svg"]); + // The last field of LaunchCreated.data: after poolKey (3 words), + // positionId, liquidity and the 11-word parameters, the offset of an ABI + // string (length, then bytes). + for (const created of events.LaunchCreated) { + const data = Buffer.from(created.data.slice(2), "hex"); + const offset = Number( + BigInt(`0x${data.subarray(16 * 32, 17 * 32).toString("hex")}`), + ); + const size = Number( + BigInt(`0x${data.subarray(offset, offset + 32).toString("hex")}`), + ); + const bytes = data.subarray(offset + 32, offset + 32 + size); + expect(utf8OrNull(bytes)).toBe(created.logo === "" ? null : created.logo); + } + expect(utf8OrNull(new Uint8Array([0x68, 0xc3]))).toBeNull(); + expect(utf8OrNull(new TextEncoder().encode("javascript:alert(1)"))).toBe( + "javascript:alert(1)", + ); +}); + +// Elapsed seconds beyond 2^63 cannot be indexed; every positive rate has +// saturated long before. +const elapsedOf = (t: string) => { + const value = BigInt(t); + return value > 1n << 63n ? 1n << 63n : value; +}; + +test("fee: every frozen fee row, table, tick step and saturation second", () => { + const fx = V.fixture; + expect(V.fee.length).toBe(40); + for (const row of V.fee) + expect( + feeAt( + BigInt(fx.fee_initial_q64), + BigInt(fx.fee_final_q64), + BigInt(row.decayRateX32), + elapsedOf(row.t_minus_start), + ).toString(), + ).toBe(row.fee_q64); + const curve = V.fee_curve; + const r = curve.rates_q64; + const d = curve.decay_rates_x32; + const f03 = BigInt(curve.final_fee_q64); + const tables: [string, bigint, bigint, bigint][] = [ + [ + "default_one_day_50_to_0.3", + BigInt(r["50"]), + f03, + BigInt(d.default_one_day), + ], + [ + "two_ticks_per_second_50_to_0.3", + BigInt(r["50"]), + f03, + BigInt(d.two_ticks_per_second), + ], + [ + "two_ticks_per_second_99.9_to_0", + BigInt(r["99.9"]), + 0n, + BigInt(d.two_ticks_per_second), + ], + ["default_one_day_max_to_0", MAX, 0n, BigInt(d.default_one_day)], + ["min_rate_max_to_0", MAX, 0n, 1n], + ]; + for (const [name, initial, final, rate] of tables) + for (const row of curve.tables[name]) + expect(feeAt(initial, final, rate, elapsedOf(row.t)).toString()).toBe( + row.fee_q64, + ); + for (const steps of curve.tick_steps) { + const initial = + BigInt(steps.rows[0].fee_q64) === f03 + 1n ? f03 + 1n : BigInt(r["50"]); + for (const row of steps.rows) + expect( + feeAt( + initial, + f03, + BigInt(steps.decayRateX32), + BigInt(row.t), + ).toString(), + ).toBe(row.fee_q64); + } + for (const [name, second] of Object.entries(curve.saturation_second)) { + const rate = BigInt(d[name]); + expect((MAX_DECAY_PRODUCT / rate).toString()).toBe(second as string); + expect(feeAt(MAX, 0n, rate, BigInt(second as string) + 1n)).toBe(0n); + } + expect(tickFactorQ128(0n)).toBe(1n << 128n); + expect(tickFactorQ128(88722835n)).toBe(18447191164202170524n); + expect(() => tickFactorQ128(88722836n)).toThrow(); +}); + +test("fee: the five SHA-256 chains the contract tests pin", async () => { + for (const chain of V.fee_curve.digests_sha256) { + let h = new Uint8Array(32); + for (let t = 0n; t <= BigInt(chain.last); t += BigInt(chain.step)) { + const fee = feeAt( + BigInt(chain.initialFee), + BigInt(chain.finalFee), + BigInt(chain.decayRateX32), + t, + ); + const word = new Uint8Array(40); + word.set(h, 0); + new DataView(word.buffer).setBigUint64(32, fee); + h = new Uint8Array(await crypto.subtle.digest("SHA-256", word)); + } + expect(Buffer.from(h).toString("hex")).toBe(chain.digest); + } +}, 120_000); + +test("schedule: decimal-string rate, exact half-life, saturation, phases, no end", () => { + const consumer = V.creator_fee_range.reference_schedules.consumer_default; + expect(decayRateForHalfLife(86400n).toString()).toBe(consumer.decayRateX32); + expect(decayRateForHalfLife(600n)).toBe(9923486534471n); + expect(HALF_LIFE_X32_E30.toString()).toBe( + "5954091920683119788732747343471285361579197626", + ); + for (const [rate, text] of [ + [68913100933n, "86400.000001"], + [9923486534471n, "600.000000"], + [1n, "5954091920683119.788732"], + [MAX, "0.000322"], + ] as const) + expect(halfLifeSeconds(rate)).toBe(text); + expect(halfLifeSeconds(0n)).toBeNull(); + const base = { + start: 1000n, + rate: BigInt(consumer.decayRateX32), + initial: BigInt(consumer.initialFee), + final: BigInt(consumer.finalFee), + }; + const at = (time: bigint, change = {}) => + feeSchedule({ ...base, ...change, time }); + expect(at(999n)).toEqual({ + trading_start: 1000, + initial_fee: consumer.initialFee, + final_fee: consumer.finalFee, + decay_rate_x32: "68913100933", + half_life_seconds: "86400.000001", + saturation_elapsed_seconds: "5529597", + phase: "before_trading_start", + fee_rate: consumer.initialFee, + evaluated_at: 999, + }); + expect(at(1000n + 86400n)).toMatchObject({ + phase: "decaying", + fee_rate: consumer.fee_after_one_day_q64, + }); + expect(at(1000n + 5529598n)).toMatchObject({ + phase: "at_floor", + fee_rate: consumer.finalFee, + }); + expect(at(5000n, { rate: 0n })).toMatchObject({ + phase: "constant", + fee_rate: consumer.initialFee, + half_life_seconds: null, + saturation_elapsed_seconds: null, + }); + expect(at(1001n, { rate: MAX })).toMatchObject({ + phase: "at_floor", + saturation_elapsed_seconds: "0", + }); + const ok = at(2000n); + expect(FeeSchedule.safeParse(ok).success).toBe(true); + for (const bad of ["18446744073709551616", "01", "-1", "1e3", "", 6891]) + expect(FeeSchedule.safeParse({ ...ok, decay_rate_x32: bad }).success).toBe( + false, + ); + for (const extra of [ + { model: "tick_rate_v2" }, + { fee_end: 1 }, + { fee_duration: 3600 }, + ]) + expect(FeeSchedule.safeParse({ ...ok, ...extra }).success).toBe(false); + for (const change of [ + { rate: 1n << 64n }, + { rate: -1n }, + { initial: 1n << 64n, final: 0n }, + { final: base.initial + 1n }, + ]) + expect(() => at(2000n, change)).toThrow(); +}); + +test("status is upcoming strictly before trading_start, trading from it on", () => { + expect(launchStatus(1000n, 999n)).toBe("upcoming"); + expect(launchStatus(1000n, 1000n)).toBe("trading"); + expect(launchStatus(1000n, 1001n)).toBe("trading"); +}); + +test("market data: exact price, market cap, raised and sold share", () => { + const Q = 1n << 128n; + // sqrt ratio 1.0: one raw quote per raw launch token in either order + expect(priceX128(Q, false)).toBe(Q); + expect(priceX128(Q, true)).toBe(Q); + // token1 per token0 = 4: a token0 launch costs 4, a token1 launch 1/4 + expect(priceX128(2n * Q, false)).toBe(4n * Q); + expect(priceX128(2n * Q, true)).toBe(Q / 4n); + expect(() => priceX128(0n, false)).toThrow(); + expect(share18(1n, 3n)).toBe("0.333333333333333333"); + expect(share18(0n, 3n)).toBe("0.000000000000000000"); + expect(share18(3n, 3n)).toBe("1.000000000000000000"); + const market = marketData({ + sqrtRatio: 2n * Q, + tick: 1386295, + launchIsToken1: true, + totalSupply: 1000n, + installed: 900n, + tokenReserve: 600n, + quoteReserve: 77n, + marketCapUsd: null, + tradeCount: 3n, + volume: 154n, + volumeUsd: null, + }); + expect(market).toEqual({ + price_tick: -1386295, + price_x128: (Q / 4n).toString(), + market_cap: "250", + market_cap_usd: null, + raised: "77", + sold: "300", + sold_share: "0.333333333333333333", + trade_count: 3, + volume: "154", + volume_usd: null, + }); + // dust above the installed amount never makes sold negative + expect( + marketData({ + ...{ sqrtRatio: Q, tick: 0, launchIsToken1: false, totalSupply: 10n }, + installed: 9n, + tokenReserve: 10n, + quoteReserve: 0n, + marketCapUsd: "1.000000", + tradeCount: 0n, + volume: 0n, + volumeUsd: "0.000000", + }).sold, + ).toBe("0"); +}); + +test("v7 schemas are final-only and closed", () => { + const keys = Object.keys(LaunchSummary.shape); + for (const key of [ + "logo_url", + "parameters", + "range", + "status", + "market", + "creator", + "owner", + "controller", + ]) + expect(keys).toContain(key); + for (const key of ["fee_model", "ask_tick", "upper_tick", "inventory"]) + expect(keys).not.toContain(key); + expect(Object.keys(LaunchDetail.shape)).toContain("fee_ledger"); + expect(Object.keys(LaunchList.shape).sort()).toEqual( + [ + "schema_version", + "data", + "total", + "totals", + "aggregates", + "next_offset", + "evaluated_at", + "heads", + ].sort(), + ); +}); diff --git a/src/routes/launches/policy.ts b/src/routes/launches/policy.ts new file mode 100644 index 0000000..5c5dd55 --- /dev/null +++ b/src/routes/launches/policy.ts @@ -0,0 +1,384 @@ +import { z } from "@hono/zod-openapi"; +import { FeeSchedule } from "./schema"; + +// sha256 of the compiled ABI JSON files of the final source freeze, +// evm-contracts 853b608ec26d4c80bdad6e394cb8ba686e1ae615 (SHA256SUMS.json of +// the freeze; copies in ./vectors/PROVENANCE.md). +export const SOURCE_COMMIT = "853b608ec26d4c80bdad6e394cb8ba686e1ae615"; +export const ABI_SHA256 = + "6a131c2d2f70f85a5e2a54395b9d77c4dd5028a7a4bbf632f3d3364ac61e56eb"; +export const PERIPHERY_ABI_SHA256 = + "5d05426f8190cb0bcd6a021e7aceb46f468708cb36bd5a5d818548650499c839"; +const NATIVE = "0x0000000000000000000000000000000000000000" as const; + +/** + * An extension and the periphery that forwards to it. An instance has no + * quote: every launch names its own (LaunchParameters.quoteToken). + */ +export interface LaunchInstance { + chainId: string; + address: string; + runtime: string; + periphery: string; + peripheryRuntime: string; + core: string; + abiSha256: string; + peripheryAbiSha256: string; +} + +/** A reviewed ERC-20 quote. Native ETH (address 0) needs no entry. */ +export interface LaunchQuote { + chainId: string; + address: string; + runtime: string; +} + +// The final contract has no deployment, so no hosted instance exists. These +// are the LOCAL instances of the indexer's replay fixture (anvil, no fork), +// accepted only by the explicit local harness. Never enable them through a +// hosted configuration. +export const LOCAL_INSTANCES: readonly LaunchInstance[] = [ + { + chainId: "31337", + address: "0x51c4ad945fbef67859d92f1690cbf86df12e3b7c", + runtime: + "0xa66e365089d80b017edeb98237831260bf9e1b7d5f3965d42be5672de6b0d70e", + periphery: "0x6963de1652c96fb0eaeaf5167de3c89e187284f2", + peripheryRuntime: + "0x208c314d799d9898e145881eefdf715d0620f13cfb343951987aba8fb8ba8363", + core: "0x00000000000014aa86c5d3c41765bb24e11bd701", + abiSha256: ABI_SHA256, + peripheryAbiSha256: PERIPHERY_ABI_SHA256, + }, +]; + +// The fixture's plain 18-decimal test ERC-20 (evm-contracts +// test/TestToken.sol), relocated to the highest address so the launch token +// is token0. Local only; the hosted quote list is empty. +export const LOCAL_QUOTES: readonly LaunchQuote[] = [ + { + chainId: "31337", + address: "0xffffffffffffffffffffffffffffffffffffffff", + runtime: + "0xe8ccd7c4eb891208d5e04a27a31dfaf2b9bce01e083d7b36f10b6dd6ea643e63", + }, +]; + +function reviewed( + requested: readonly T[], + pins: readonly T[], + localHarness: boolean, +): readonly T[] { + if (!localHarness) return []; + return requested.filter((request) => + pins.some((pin) => + (Object.keys(pin) as (keyof T)[]).every( + (key) => pin[key] === request[key], + ), + ), + ); +} + +/** An explicit local harness manifest, never an address-only allowlist. */ +export function supportedInstances( + requested: readonly LaunchInstance[], + localHarness: boolean, + pins: readonly LaunchInstance[] = LOCAL_INSTANCES, +): readonly LaunchInstance[] { + return reviewed(requested, pins, localHarness); +} + +/** ERC-20 quotes bound by chain, address and runtime; empty when hosted. */ +export function supportedQuotes( + requested: readonly LaunchQuote[], + localHarness: boolean, + pins: readonly LaunchQuote[] = LOCAL_QUOTES, +): readonly LaunchQuote[] { + return reviewed(requested, pins, localHarness); +} + +/** Native ETH, or an ERC-20 in the enabled quote list of the chain. */ +export function supportedQuote( + row: { chainId: string; quote: string; quoteKind: "native" | "erc20" }, + quotes: readonly LaunchQuote[], +): boolean { + if (row.quoteKind === "native") return row.quote === NATIVE; + return ( + row.quote !== NATIVE && + quotes.some((q) => q.chainId === row.chainId && q.address === row.quote) + ); +} + +export const SINK_HOLDER = NATIVE; +const MAX_SUPPLY = 10n ** 30n; + +/** + * requested (LaunchParameters.supply, totalSupply), installed (in the + * position) and sink (minted to address 0). Anything outside + * 0 < installed <= requested <= 10^30 with sink = requested - installed is + * malformed indexed data. + */ +export function launchSupply(input: { + requested: bigint; + installed: bigint; + sink: bigint; +}) { + const { requested, installed, sink } = input; + if ( + installed <= 0n || + installed > requested || + requested > MAX_SUPPLY || + sink !== requested - installed + ) { + throw new Error("Invalid indexed launch supply"); + } + return { + requested: requested.toString(), + installed: installed.toString(), + sink: sink.toString(), + sink_holder: SINK_HOLDER, + }; +} + +/** + * The content of a canonical LibString.packOne word: byte 0 is the length + * (1..31), then the content, then zeros. Returns the UTF-8 text, or null + * when the content is not valid UTF-8. A non-canonical word is malformed + * indexed data: the contract refuses it. + */ +export function unpackString(word: bigint): string | null { + if (word < 0n || word >= 1n << 256n) throw new Error("Invalid packed word"); + const length = Number(word >> 248n); + const tailBits = BigInt(8 * (31 - length)); + if (length === 0 || length > 31 || (word & ((1n << tailBits) - 1n)) !== 0n) { + throw new Error("Invalid indexed packed string"); + } + const bytes = new Uint8Array(length); + for (let i = 0; i < length; i++) + bytes[i] = Number((word >> BigInt(8 * (30 - i))) & 0xffn); + return utf8OrNull(bytes); +} + +/** UTF-8 text of `bytes`, null when empty or not valid UTF-8. Never rewritten. */ +export function utf8OrNull(bytes: Uint8Array): string | null { + if (bytes.length === 0) return null; + try { + return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode( + bytes, + ); + } catch { + return null; + } +} + +/** Derived spacing and signed-aligned economic bounds of the installation. */ +export function alignedRange(ask: number, upper: number) { + if (!(ask < upper)) throw new Error("Invalid indexed ticks"); + const spacing = Math.floor((upper - ask + 255) / 256); + return { + tick_spacing: spacing, + aligned_ask_tick: Math.ceil(ask / spacing) * spacing, + aligned_upper_tick: Math.floor(upper / spacing) * spacing, + }; +} + +const UINT64_MAX = (1n << 64n) - 1n; +function uint64(value: bigint) { + if (value < 0n || value > UINT64_MAX) { + throw new Error("Invalid indexed uint64"); + } + return value; +} + +// JSON Unix seconds must be exactly representable; never round indexed time. +export function seconds(value: bigint) { + uint64(value); + if (value > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error("Indexed time exceeds exact JSON integer domain"); + } + return Number(value); +} + +const Q128 = 1n << 128n; +/** Largest tick magnitude of the contracts' tick helper. */ +export const MAX_TICK_MAGNITUDE = 88722835n; +/** (MAX_TICK_MAGNITUDE + 1) * 2^32 - 1: the saturation numerator. */ +export const MAX_DECAY_PRODUCT = ((MAX_TICK_MAGNITUDE + 1n) << 32n) - 1n; +/** + * floor(2 * ln 2 / ln 1.000001 * 2^32 * 10^30): ticks per half-life of the + * excess, Q32.32, scaled by 10^30. The normative integer for every half-life + * conversion; never a float. + */ +export const HALF_LIFE_X32_E30 = + 5954091920683119788732747343471285361579197626n; +/** The bit constants of tickToSqrtRatio for negative ticks (math/ticks.sol). */ +const TICK_MASKS: readonly bigint[] = [ + 340282196779882608775400081051345954875n, + 340282026638911824551550055881712329744n, + 340281686357225467326082729798982530761n, + 340281005794873596573094710012989410072n, + 340279644674253220331048947518555486588n, + 340276922449345852680114346161748269428n, + 340271478064864046934932689706268169160n, + 340260589557227275536970734808027446368n, + 340238813587222069206590352882444122789n, + 340195265827972829906238800850533898084n, + 340108187030021964395011332102514443192n, + 339934096296338836553381438728885759063n, + 339586182118148867994722769619739863337n, + 338891421642114786711725022995822495130n, + 337506162020136007223375792700736547955n, + 334752606878476170032608184381010470119n, + 329312708224965356314372077522414179198n, + 318696677643769341895946499718036526719n, + 298480268784467865547185399201474874621n, + 261813363001402740542020888190605903085n, + 201439286044552466954512953679502885114n, + 119247395418425876229630149779831629514n, + 41788651709309085859755118322591422179n, + 5131889223303998677939799486543748348n, + 77395391476111124436543048938586576n, + 17603164912545197391926702422886n, + 910630244353091011850553n, +]; + +/** + * toFixed(tickToSqrtRatio(-magnitude)): from 2^128, multiply by the constant + * of every set bit in ascending order and floor after each multiply, then + * round down to the compact 94-bit mantissa of its region. + */ +export function tickFactorQ128(magnitude: bigint): bigint { + if (magnitude < 0n || magnitude > MAX_TICK_MAGNITUDE) + throw new Error("Tick magnitude out of range"); + let ratio = Q128; + TICK_MASKS.forEach((mask, bit) => { + if ((magnitude >> BigInt(bit)) & 1n) ratio = (ratio * mask) >> 128n; + }); + const shift = ratio >= Q128 ? 66n : ratio >= 1n << 96n ? 34n : 2n; + return (ratio >> shift) << shift; +} + +/** + * feeAt of the contract in its normative order: initial before and at the + * start and for rate 0; elapsed > MAX_DECAY_PRODUCT / rate (integer division + * first) is final, the floor; otherwise + * final + floor((initial - final) * tickFactorQ128(floor(rate * elapsed / 2^32)) / 2^128). + */ +export function feeAt( + initial: bigint, + final: bigint, + rate: bigint, + elapsed: bigint, +): bigint { + if (elapsed <= 0n || rate === 0n) return initial; + if (elapsed > MAX_DECAY_PRODUCT / rate) return final; + return ( + final + + (((initial - final) * tickFactorQ128((rate * elapsed) >> 32n)) >> 128n) + ); +} + +/** decayRateX32 for a half-life of `seconds` (> 0): floor(HALF_LIFE_X32_E30 / (seconds * 10^30)). */ +export function decayRateForHalfLife(seconds: bigint): bigint { + if (seconds <= 0n) throw new Error("Half-life must be positive"); + return HALF_LIFE_X32_E30 / (seconds * 10n ** 30n); +} + +/** The half-life of the excess, 6 fractional digits, floored; null for rate 0. Display only. */ +export function halfLifeSeconds(rate: bigint): string | null { + if (rate === 0n) return null; + const micros = HALF_LIFE_X32_E30 / (rate * 10n ** 24n); + const fraction = (micros % 1_000_000n).toString().padStart(6, "0"); + return `${micros / 1_000_000n}.${fraction}`; +} + +/** The served schedule; anything outside the contract's domain is malformed (500). */ +export function feeSchedule(input: { + start: bigint; + initial: bigint; + final: bigint; + rate: bigint; + time: bigint; +}): z.infer { + const { start, initial, final, rate, time } = input; + [start, initial, final, rate, time].forEach(uint64); + if (final > initial) throw new Error("Invalid indexed fee schedule"); + const fee = feeAt(initial, final, rate, time - start); + let phase: z.infer["phase"]; + if (time < start) phase = "before_trading_start"; + else if (fee === final) phase = "at_floor"; + else if (rate === 0n) phase = "constant"; + else phase = "decaying"; + return { + trading_start: seconds(start), + initial_fee: initial.toString(), + final_fee: final.toString(), + decay_rate_x32: rate.toString(), + half_life_seconds: halfLifeSeconds(rate), + saturation_elapsed_seconds: + rate === 0n ? null : (MAX_DECAY_PRODUCT / rate).toString(), + phase, + fee_rate: fee.toString(), + evaluated_at: seconds(time), + }; +} + +/** upcoming before trading_start, trading from it on. */ +export function launchStatus(start: bigint, time: bigint) { + return time < start ? ("upcoming" as const) : ("trading" as const); +} + +/** + * Raw quote per raw launch token times 2^128, floored, from Core's Q128 + * sqrt ratio (token1 per token0). + */ +export function priceX128(sqrtRatio: bigint, launchIsToken1: boolean) { + if (sqrtRatio <= 0n) throw new Error("Invalid indexed sqrt ratio"); + const square = sqrtRatio * sqrtRatio; + return launchIsToken1 ? (1n << 384n) / square : square >> 128n; +} + +/** floor(fraction * 10^18) of numerator / denominator as "d.dddddddddddddddddd". */ +export function share18(numerator: bigint, denominator: bigint) { + if (denominator <= 0n || numerator < 0n || numerator > denominator) + throw new Error("Invalid indexed share"); + const scaled = (numerator * 10n ** 18n) / denominator; + return `${scaled / 10n ** 18n}.${(scaled % 10n ** 18n).toString().padStart(18, "0")}`; +} + +/** + * Market data from the indexed Core state: price, market cap (price times + * totalSupply), raised quote and the sold launch tokens. + */ +export function marketData(input: { + sqrtRatio: bigint; + tick: number; + launchIsToken1: boolean; + totalSupply: bigint; + installed: bigint; + tokenReserve: bigint; + quoteReserve: bigint; + marketCapUsd: string | null; + tradeCount: bigint; + volume: bigint; + volumeUsd: string | null; +}) { + const price = priceX128(input.sqrtRatio, input.launchIsToken1); + const left = + input.tokenReserve > input.installed ? input.installed : input.tokenReserve; + if (input.tokenReserve < 0n || input.quoteReserve < 0n) + throw new Error("Invalid indexed reserves"); + const sold = input.installed - left; + return { + price_tick: input.launchIsToken1 ? -input.tick : input.tick, + price_x128: price.toString(), + market_cap: ((price * input.totalSupply) >> 128n).toString(), + market_cap_usd: input.marketCapUsd, + raised: input.quoteReserve.toString(), + sold: sold.toString(), + sold_share: share18(sold, input.installed), + trade_count: Number(input.tradeCount), + volume: input.volume.toString(), + volume_usd: input.volumeUsd, + }; +} diff --git a/src/routes/launches/queries.ts b/src/routes/launches/queries.ts new file mode 100644 index 0000000..6dc32a4 --- /dev/null +++ b/src/routes/launches/queries.ts @@ -0,0 +1,802 @@ +import type postgres from "postgres"; +import type { Sql } from "postgres"; +import { z } from "@hono/zod-openapi"; +import { StatusError } from "../../shared/errors"; +import { + alignedRange, + feeSchedule, + launchStatus, + launchSupply, + marketData, + seconds, + supportedInstances, + supportedQuotes, + unpackString, + utf8OrNull, + type LaunchInstance, + type LaunchQuote, +} from "./policy"; +import { + BlockRef, + ClaimPage, + LaunchDetail, + LaunchList, + OwnerPage, + SCHEMA_VERSION, + SwapPage, +} from "./schema"; + +type DB = Sql<{ bigint: bigint }>; +type Numeric = string | bigint; +type Head = z.infer; +interface EventRow { + event_id: bigint; + block_number: bigint; + block_hash: Numeric; + block_time: Date; + transaction_index: number; + event_index: number; + transaction_hash: Numeric; +} +interface LaunchRow extends EventRow { + chain_id: bigint; + pool_id: Numeric; + pool_key_id: bigint; + core_address: Numeric; + emitter: Numeric; + token0: Numeric; + token1: Numeric; + token: Numeric; + quote_token: Numeric; + quote_kind: "native" | "erc20"; + controller: Numeric; + initial_owner: Numeric; + current_owner: Numeric; + owner_change_count: bigint; + name_word: Numeric; + symbol_word: Numeric; + logo_url_bytes: Uint8Array; + quote_name: string | null; + quote_symbol: string | null; + quote_decimals: number | null; + token_is_token1: boolean; + ask_tick: number; + upper_tick: number; + tick_spacing: bigint; + aligned_ask_tick: number; + aligned_upper_tick: number; + tick_lower: number; + tick_upper: number; + trading_start: Numeric; + decay_rate_x32: Numeric; + initial_fee: Numeric; + final_fee: Numeric; + salt: Numeric; + position_id: Numeric; + liquidity: Numeric; + requested_supply: Numeric; + installed_supply: Numeric; + sink_supply: Numeric; + balance0: Numeric; + balance1: Numeric; + sqrt_ratio: Numeric; + tick: number; + accrued0: Numeric; + accrued1: Numeric; + claimed0: Numeric; + claimed1: Numeric; + swap_count: bigint; + claim_count: bigint; + last_event_id: bigint; + market_cap_usd: string | null; + volume: Numeric; + volume_usd: string | null; +} +const decimal = (n: Numeric) => n.toString(); +const hex = (n: Numeric, width: number) => + `0x${BigInt(n) + .toString(16) + .padStart(width * 2, "0")}`; +const epoch = (date: Date) => Math.floor(date.getTime() / 1000); +function parseIndexed( + schema: T, + value: unknown, +): z.output { + const result = schema.safeParse(value); + if (!result.success) throw new Error("Invalid indexed launch data"); + return result.data; +} +function event(row: EventRow) { + return { + event_id: decimal(row.event_id), + block_number: decimal(row.block_number), + block_hash: hex(row.block_hash, 32), + block_time: epoch(row.block_time), + transaction_index: row.transaction_index, + event_index: row.event_index, + transaction_hash: hex(row.transaction_hash, 32), + }; +} +// The installed range must be the one the contract derives from the +// requested ticks; anything else is malformed indexed data. +function range(row: LaunchRow) { + const derived = alignedRange(row.ask_tick, row.upper_tick); + const [lower, upper] = row.token_is_token1 + ? [-derived.aligned_upper_tick, -derived.aligned_ask_tick] + : [derived.aligned_ask_tick, derived.aligned_upper_tick]; + if ( + derived.tick_spacing !== Number(row.tick_spacing) || + derived.aligned_ask_tick !== row.aligned_ask_tick || + derived.aligned_upper_tick !== row.aligned_upper_tick || + lower !== row.tick_lower || + upper !== row.tick_upper + ) + throw new Error("Invalid indexed launch range"); + return { ...derived, pool_tick_lower: lower, pool_tick_upper: upper }; +} +function summary(row: LaunchRow, asOf: Head, time: bigint) { + const start = BigInt(row.trading_start); + const [tokenReserve, quoteReserve] = row.token_is_token1 + ? [row.balance1, row.balance0] + : [row.balance0, row.balance1]; + const supply = launchSupply({ + requested: BigInt(row.requested_supply), + installed: BigInt(row.installed_supply), + sink: BigInt(row.sink_supply), + }); + return { + schema_version: SCHEMA_VERSION, + chain_id: decimal(row.chain_id), + pool_id: hex(row.pool_id, 32), + pool_key: { + core_address: hex(row.core_address, 20), + token0: hex(row.token0, 20), + token1: hex(row.token1, 20), + config: hex( + (BigInt(row.emitter) << 96n) | (1n << 31n) | row.tick_spacing, + 32, + ), + fee: "0" as const, + tick_spacing: Number(row.tick_spacing), + extension: hex(row.emitter, 20), + }, + token: { + address: hex(row.token, 20), + name: unpackString(BigInt(row.name_word)), + symbol: unpackString(BigInt(row.symbol_word)), + decimals: 18 as const, + }, + quote_token: quoteToken(row), + launch_token_is_token1: row.token_is_token1, + controller: hex(row.controller, 20), + creator: hex(row.initial_owner, 20), + owner: hex(row.current_owner, 20), + logo_url: utf8OrNull(row.logo_url_bytes), + parameters: { + name: hex(row.name_word, 32), + symbol: hex(row.symbol_word, 32), + supply: supply.requested, + quote_token: hex(row.quote_token, 20), + ask_tick: row.ask_tick.toString(), + upper_tick: row.upper_tick.toString(), + trading_start: decimal(row.trading_start), + decay_rate_x32: decimal(row.decay_rate_x32), + initial_fee: decimal(row.initial_fee), + final_fee: decimal(row.final_fee), + salt: hex(row.salt, 32), + }, + range: range(row), + supply, + trading_start: seconds(start), + status: launchStatus(start, time), + fee_schedule: feeSchedule({ + start, + initial: BigInt(row.initial_fee), + final: BigInt(row.final_fee), + rate: BigInt(row.decay_rate_x32), + time, + }), + market: marketData({ + sqrtRatio: BigInt(row.sqrt_ratio), + tick: row.tick, + launchIsToken1: row.token_is_token1, + totalSupply: BigInt(row.requested_supply), + installed: BigInt(row.installed_supply), + tokenReserve: BigInt(tokenReserve), + quoteReserve: BigInt(quoteReserve), + marketCapUsd: row.market_cap_usd, + tradeCount: row.swap_count, + volume: BigInt(row.volume), + volumeUsd: row.volume_usd, + }), + created: event(row), + as_of: asOf, + }; +} +// Native ETH has no token contract: 18 decimals, no ERC-20 metadata. +function quoteToken(row: LaunchRow) { + if (row.quote_kind === "native") + return { + address: hex(row.quote_token, 20), + name: null, + symbol: null, + decimals: 18, + kind: "native" as const, + }; + return { + address: hex(row.quote_token, 20), + name: row.quote_name, + symbol: row.quote_symbol, + decimals: row.quote_decimals, + kind: "erc20" as const, + }; +} +function ledger(accrued: Numeric, claimed: Numeric) { + return { + accrued: decimal(accrued), + claimed: decimal(claimed), + unclaimed: (BigInt(accrued) - BigInt(claimed)).toString(), + }; +} +function detail(row: LaunchRow, asOf: Head, time: bigint) { + const launch = summary(row, asOf, time); + const [tokenBalance, quoteBalance] = row.token_is_token1 + ? [row.balance1, row.balance0] + : [row.balance0, row.balance1]; + const [tokenSide, quoteSide] = row.token_is_token1 + ? [ledger(row.accrued1, row.claimed1), ledger(row.accrued0, row.claimed0)] + : [ledger(row.accrued0, row.claimed0), ledger(row.accrued1, row.claimed1)]; + return parseIndexed(LaunchDetail, { + ...launch, + principal: { + position_id: hex(row.position_id, 32), + liquidity: decimal(row.liquidity), + locked: true, + withdrawable: false, + pool_reserves: { + launch_token: decimal(tokenBalance), + quote_token: decimal(quoteBalance), + }, + }, + fee_ledger: { + holder: launch.owner, + launch_token: tokenSide, + quote_token: quoteSide, + swap_count: Number(row.swap_count), + claim_count: Number(row.claim_count), + owner_change_count: Number(row.owner_change_count), + last_event_id: decimal(row.last_event_id), + }, + }); +} + +export type LaunchStatusFilter = "all" | "trading" | "upcoming"; +export type LaunchOrder = + | "market_cap" + | "volume" + | "sold_share" + | "trade_count" + | "created"; + +export interface LaunchReadOptions { + chainId: bigint; + cursor?: bigint; + limit: number; +} + +export interface LaunchListOptions { + chainId?: bigint; + status: LaunchStatusFilter; + owner?: bigint; + creator?: bigint; + orderBy: LaunchOrder; + offset: number; + limit: number; +} + +interface ReaderOptions { + localHarness: boolean; + instances: readonly LaunchInstance[]; + quotes: readonly LaunchQuote[]; + maxIndexAgeSeconds: number; + /** Seconds since the epoch at which status and fee rate are evaluated. */ + now?: () => bigint; + /** The reviewed manifests the requested lists must match (tests only). */ + pins?: { + instances: readonly LaunchInstance[]; + quotes: readonly LaunchQuote[]; + }; +} + +const HOSTED: ReaderOptions = { + localHarness: false, + instances: [], + quotes: [], + maxIndexAgeSeconds: 60, +}; +const wallClock = () => BigInt(Math.floor(Date.now() / 1000)); + +/** All constituent reads share a read-only repeatable-read snapshot. */ +export class LaunchQueries { + private readonly enabled: readonly LaunchInstance[]; + private readonly quotes: readonly LaunchQuote[]; + private readonly maxAge: number; + private readonly now: () => bigint; + constructor( + private readonly sql: DB, + options: ReaderOptions = HOSTED, + ) { + this.enabled = supportedInstances( + options.instances, + options.localHarness, + options.pins?.instances, + ); + this.quotes = supportedQuotes( + options.quotes, + options.localHarness, + options.pins?.quotes, + ); + this.maxAge = options.maxIndexAgeSeconds; + this.now = options.now ?? wallClock; + if (!Number.isFinite(this.maxAge) || this.maxAge <= 0) { + throw new Error("Invalid local index freshness bound"); + } + } + + /** The enabled chains a request covers; none is a disabled launch read. */ + private chains(chainId?: bigint): string[] { + const chains = [...new Set(this.enabled.map((p) => p.chainId))] + .filter((c) => chainId === undefined || c === chainId.toString()) + .sort((a, b) => (BigInt(a) < BigInt(b) ? -1 : 1)); + if (chains.length === 0) + throw new StatusError(404, "Launch support is disabled"); + return chains; + } + + private async head(db: DB, chainId: string): Promise { + const [head] = await db< + { + block_number: bigint; + block_hash: Numeric; + block_time: Date; + last_updated: Date; + }[] + >` + SELECT b.block_number, b.block_hash, b.block_time, ic.last_updated + FROM indexer_cursor ic JOIN blocks b + ON b.chain_id = ic.chain_id AND b.block_number = ic.head_block_number + AND b.block_hash = ic.head_block_hash + WHERE ic.chain_id = ${chainId} + `; + if (!head || Date.now() - head.last_updated.getTime() > this.maxAge * 1000) + throw new StatusError( + 503, + `Launch index for chain ${chainId} is stale or has no coherent head`, + ); + return parseIndexed(BlockRef, { + block_number: decimal(head.block_number), + block_hash: hex(head.block_hash, 32), + block_time: epoch(head.block_time), + }); + } + + private async snapshot( + chains: string[], + read: (tx: DB, heads: Map, time: bigint) => Promise, + ): Promise { + const time = this.now(); + return this.sql.begin( + "isolation level repeatable read read only", + async (tx) => { + const db = tx as unknown as DB; + const heads = new Map(); + for (const chain of chains) + heads.set(chain, await this.head(db, chain)); + return read(db, heads, time); + }, + ) as Promise; + } + + /** + * Supported launches of the given chains. Screening happens in SQL before + * any order, offset or limit, so an unsupported launch never takes a slot. + */ + private rows(tx: DB, chains: string[], filter: postgres.Fragment) { + const pins = this.enabled.filter((p) => chains.includes(p.chainId)); + // Only launches created through the instance's periphery have an owner. + const instance = pins + .map( + (p) => tx` + (c.chain_id = ${p.chainId}::int8 + AND c.emitter = ${BigInt(p.address).toString()}::numeric + AND c.controller = ${BigInt(p.periphery).toString()}::numeric + AND pk.core_address = ${BigInt(p.core).toString()}::numeric) + `, + ) + .reduce((a, b) => tx`${a} OR ${b}`); + // The launch's own quote: native ETH, or a reviewed ERC-20 of the chain. + const erc20 = this.quotes + .filter((q) => chains.includes(q.chainId)) + .map( + (q) => + tx`(c.chain_id = ${q.chainId}::int8 AND c.quote_token = ${BigInt(q.address).toString()}::numeric)`, + ) + .reduce((a, b) => tx`${a} OR ${b}`, tx`FALSE`); + const chainList = chains + .map((chain) => tx`${chain}::int8`) + .reduce((a, b) => tx`${a}, ${b}`); + const quote = tx` + ((c.quote_kind = 'native' AND c.quote_token = 0) + OR (c.quote_kind = 'erc20' AND c.quote_token <> 0 AND (${erc20}))) + `; + // price_x128 = raw quote per raw launch token * 2^128 (Core's sqrt ratio + // is Q128 token1 per token0); market cap = price * totalSupply. volume is + // |quote delta| summed over every LaunchSwapped, fee-inclusive. The USD + // values use the indexed quote price; the *_quote columns (whole quote + // units) and sold_share_e18 exist only to order by. + return tx` + SELECT l.*, m.market_cap::text AS market_cap, + CASE WHEN l.quote_price IS NULL THEN NULL + ELSE ROUND(m.market_cap / POWER(10::numeric, l.quote_decimals_effective) + * l.quote_price::numeric, 6)::text END AS market_cap_usd, + CASE WHEN l.quote_price IS NULL THEN NULL + ELSE ROUND(l.volume / POWER(10::numeric, l.quote_decimals_effective) + * l.quote_price::numeric, 6)::text END AS volume_usd, + m.market_cap / POWER(10::numeric, l.quote_decimals_effective) AS market_cap_quote, + l.volume / POWER(10::numeric, l.quote_decimals_effective) AS volume_quote, + DIV((l.installed_supply - LEAST(l.token_reserve, l.installed_supply)) + * 1000000000000000000, NULLIF(l.installed_supply, 0)) AS sold_share_e18 + FROM ( + SELECT c.*, b.block_hash, b.block_time, pk.core_address, pk.token0, pk.token1, + qt.token_name AS quote_name, qt.token_symbol AS quote_symbol, + qt.token_decimals AS quote_decimals, + CASE WHEN c.quote_kind = 'native' THEN 18 ELSE qt.token_decimals END AS quote_decimals_effective, + qp.value AS quote_price, + s.accrued0, s.accrued1, s.claimed0, s.claimed1, s.swap_count, s.claim_count, + s.last_event_id, s.initial_owner, s.current_owner, s.owner_change_count, + pt.balance0, pt.balance1, ps.tick, ps.sqrt_ratio, v.volume, + CASE WHEN c.token_is_token1 THEN pt.balance1 ELSE pt.balance0 END AS token_reserve, + CASE WHEN c.token_is_token1 + THEN DIV(POWER(2::numeric, 384), ps.sqrt_ratio * ps.sqrt_ratio) + ELSE DIV(ps.sqrt_ratio * ps.sqrt_ratio, 340282366920938463463374607431768211456) END AS price_x128 + FROM zero_seed_launch_created c + JOIN zero_seed_launch_pool_keys registration USING (pool_key_id) + JOIN pool_keys pk USING (pool_key_id) + JOIN blocks b ON b.chain_id = c.chain_id AND b.block_number = c.block_number + JOIN zero_seed_launch_states s USING (pool_key_id) + JOIN pool_states ps USING (pool_key_id) + JOIN pool_tvl pt USING (pool_key_id) + LEFT JOIN erc20_tokens qt ON qt.chain_id = c.chain_id AND qt.token_address = c.quote_token + AND c.quote_kind = 'erc20' + LEFT JOIN erc20_tokens_latest_price qp ON qp.chain_id = c.chain_id AND qp.token_address = c.quote_token + CROSS JOIN LATERAL ( + SELECT COALESCE(SUM(ABS(CASE WHEN c.token_is_token1 THEN w.delta0 ELSE w.delta1 END)), 0) AS volume + FROM zero_seed_launch_swapped w WHERE w.pool_key_id = c.pool_key_id + ) v + WHERE c.chain_id IN (${chainList}) AND pk.chain_id = c.chain_id + AND pk.pool_extension = c.emitter AND pk.fee = 0 + AND pk.token0 = LEAST(c.token, c.quote_token) + AND pk.token1 = GREATEST(c.token, c.quote_token) + AND pk.tick_spacing = c.tick_spacing + AND s.current_owner IS NOT NULL AND s.initial_owner IS NOT NULL + AND (${instance}) AND ${quote} AND ${filter} + ) l + CROSS JOIN LATERAL ( + SELECT DIV(l.price_x128 * l.requested_supply, 340282366920938463463374607431768211456) AS market_cap + ) m + `; + } + + async list(input: LaunchListOptions) { + const chains = this.chains(input.chainId); + return this.snapshot(chains, async (tx, heads, time) => { + const creator = input.creator?.toString() ?? null; + const owner = input.owner?.toString() ?? null; + const filter = tx` + (${creator}::numeric IS NULL OR s.initial_owner = ${creator}::numeric) + AND (${owner}::numeric IS NULL OR s.current_owner = ${owner}::numeric) + `; + const now = time.toString(); + const status = { + all: tx`TRUE`, + trading: tx`l.trading_start <= ${now}::numeric`, + upcoming: tx`l.trading_start > ${now}::numeric`, + }[input.status]; + const [counts] = await tx< + { all: number; trading: number; upcoming: number }[] + >` + SELECT COUNT(*)::int AS all, + (COUNT(*) FILTER (WHERE l.trading_start <= ${now}::numeric))::int AS trading, + (COUNT(*) FILTER (WHERE l.trading_start > ${now}::numeric))::int AS upcoming + FROM (${this.rows(tx, chains, filter)}) l + `; + const groups = await tx` + SELECT l.chain_id, l.quote_token, COUNT(*)::int AS launch_count, + SUM(l.swap_count)::text AS trade_count, SUM(l.volume)::text AS volume, + SUM(l.market_cap::numeric)::text AS market_cap, + SUM(l.volume_usd::numeric)::text AS volume_usd, + SUM(l.market_cap_usd::numeric)::text AS market_cap_usd + FROM (${this.rows(tx, chains, filter)}) l + WHERE ${status} + GROUP BY l.chain_id, l.quote_token ORDER BY l.chain_id, l.quote_token + `; + // The whole filtered set is ordered before the page is cut; the + // creation order breaks ties. + const rows = await tx` + SELECT * FROM (${this.rows(tx, chains, filter)}) l + WHERE ${status} + ORDER BY ${orderBy(tx, input.orderBy)}, block_time DESC, chain_id, event_id DESC + OFFSET ${input.offset} LIMIT ${input.limit + 1} + `; + const page = rows.slice(0, input.limit); + return parseIndexed(LaunchList, { + schema_version: SCHEMA_VERSION, + data: page.map((r) => + summary(r, heads.get(r.chain_id.toString())!, time), + ), + total: counts[input.status], + totals: counts, + aggregates: aggregates(groups), + next_offset: + rows.length > input.limit ? input.offset + input.limit : null, + evaluated_at: seconds(time), + heads: chains.map((chain) => ({ + chain_id: chain, + ...heads.get(chain)!, + })), + }); + }); + } + + private async launch(tx: DB, chainId: bigint, poolId: bigint) { + const [row] = await this.rows( + tx, + [chainId.toString()], + tx`c.pool_id = ${poolId.toString()}::numeric`, + ); + if (!row) throw new StatusError(404, "Launch not found"); + return row; + } + + async detail(chainId: bigint, poolId: bigint) { + return this.snapshot(this.chains(chainId), async (tx, heads, time) => + detail( + await this.launch(tx, chainId, poolId), + heads.get(chainId.toString())!, + time, + ), + ); + } + + private page( + schema: T, + input: LaunchReadOptions & { poolId: bigint }, + asOf: Head, + data: { event: { event_id: string } }[], + more: boolean, + extra: object = {}, + ) { + return parseIndexed(schema, { + schema_version: SCHEMA_VERSION, + chain_id: input.chainId.toString(), + pool_id: hex(input.poolId, 32), + as_of: asOf, + data, + next_cursor: more ? data.at(-1)!.event.event_id : null, + ...extra, + }); + } + + async swaps(input: LaunchReadOptions & { poolId: bigint }) { + const chains = this.chains(input.chainId); + return this.snapshot(chains, async (tx, heads) => { + const launch = await this.launch(tx, input.chainId, input.poolId); + const rows = await tx< + (EventRow & { + locker: Numeric; + delta0: Numeric; + delta1: Numeric; + fee_rate: Numeric; + fee_amount: Numeric; + fee_is_token1: boolean; + })[] + >` + SELECT s.*, b.block_hash, b.block_time FROM zero_seed_launch_swapped s + JOIN blocks b ON b.chain_id = s.chain_id AND b.block_number = s.block_number + WHERE s.pool_key_id = ${launch.pool_key_id} + AND (${input.cursor ?? null}::int8 IS NULL OR s.event_id > ${input.cursor ?? null}) + ORDER BY s.event_id LIMIT ${input.limit + 1} + `; + const data = rows.slice(0, input.limit).map((row) => { + const [token, quote] = launch.token_is_token1 + ? [row.delta1, row.delta0] + : [row.delta0, row.delta1]; + return { + event: event(row), + forwarding_locker: hex(row.locker, 20), + direction: swapDirection(BigInt(token), BigInt(quote)), + launch_token_delta: decimal(token), + quote_token_delta: decimal(quote), + fee_rate: decimal(row.fee_rate), + fee_amount: decimal(row.fee_amount), + fee_asset: + row.fee_is_token1 === launch.token_is_token1 + ? "launch_token" + : "quote_token", + }; + }); + return this.page( + SwapPage, + input, + heads.get(chains[0])!, + data, + rows.length > input.limit, + ); + }); + } + + async claims(input: LaunchReadOptions & { poolId: bigint }) { + const chains = this.chains(input.chainId); + return this.snapshot(chains, async (tx, heads) => { + const launch = await this.launch(tx, input.chainId, input.poolId); + // One row per claim, keyed on the extension event; the periphery + // payout of the same transaction only names owner and recipient. A + // periphery launch always has its payout; one without is malformed. + const rows = await tx< + (EventRow & { + payout_event_id: bigint | null; + owner: Numeric | null; + recipient: Numeric | null; + amount0: Numeric; + amount1: Numeric; + })[] + >` + SELECT cl.event_id, cl.block_number, cl.transaction_index, cl.event_index, + cl.transaction_hash, cl.payout_event_id, cl.owner, cl.recipient, + cl.amount0, cl.amount1, b.block_hash, b.block_time + FROM zero_seed_launch_claims cl + JOIN blocks b ON b.chain_id = cl.chain_id AND b.block_number = cl.block_number + WHERE cl.pool_key_id = ${launch.pool_key_id} + AND (${input.cursor ?? null}::int8 IS NULL OR cl.event_id > ${input.cursor ?? null}) + ORDER BY cl.event_id LIMIT ${input.limit + 1} + `; + const data = rows.slice(0, input.limit).map((row) => { + if ( + row.payout_event_id === null || + row.owner === null || + row.recipient === null + ) + throw new Error("Invalid indexed claim without its payout"); + return { + event: event(row), + payout_event_id: decimal(row.payout_event_id), + owner: hex(row.owner, 20), + recipient: hex(row.recipient, 20), + launch_token_amount: decimal( + launch.token_is_token1 ? row.amount1 : row.amount0, + ), + quote_token_amount: decimal( + launch.token_is_token1 ? row.amount0 : row.amount1, + ), + }; + }); + const [tokenClaimed, quoteClaimed] = launch.token_is_token1 + ? [launch.claimed1, launch.claimed0] + : [launch.claimed0, launch.claimed1]; + return this.page( + ClaimPage, + input, + heads.get(chains[0])!, + data, + rows.length > input.limit, + { + totals: { + launch_token: decimal(tokenClaimed), + quote_token: decimal(quoteClaimed), + }, + }, + ); + }); + } + + async owners(input: LaunchReadOptions & { poolId: bigint }) { + const chains = this.chains(input.chainId); + return this.snapshot(chains, async (tx, heads) => { + const launch = await this.launch(tx, input.chainId, input.poolId); + const rows = await tx< + (EventRow & { previous_owner: Numeric; new_owner: Numeric })[] + >` + SELECT o.*, b.block_hash, b.block_time FROM zero_seed_launch_owner_changed o + JOIN blocks b ON b.chain_id = o.chain_id AND b.block_number = o.block_number + WHERE o.pool_key_id = ${launch.pool_key_id} + AND (${input.cursor ?? null}::int8 IS NULL OR o.event_id > ${input.cursor ?? null}) + ORDER BY o.event_id LIMIT ${input.limit + 1} + `; + const data = rows.slice(0, input.limit).map((row) => ({ + event: event(row), + previous_owner: + BigInt(row.previous_owner) === 0n + ? null + : hex(row.previous_owner, 20), + new_owner: hex(row.new_owner, 20), + })); + return this.page( + OwnerPage, + input, + heads.get(chains[0])!, + data, + rows.length > input.limit, + ); + }); + } +} + +// Launches without a USD value rank after those with one, by whole quote +// units, so launches on different quotes still compare. +function orderBy(tx: DB, key: LaunchOrder) { + return { + market_cap: tx`(market_cap_usd IS NULL), market_cap_usd::numeric DESC, market_cap_quote DESC NULLS LAST`, + volume: tx`(volume_usd IS NULL), volume_usd::numeric DESC, volume_quote DESC NULLS LAST`, + sold_share: tx`sold_share_e18 DESC NULLS LAST`, + trade_count: tx`swap_count DESC`, + created: tx`block_time DESC`, + }[key]; +} + +interface QuoteGroup { + chain_id: bigint; + quote_token: Numeric; + launch_count: number; + trade_count: string; + volume: string; + market_cap: string; + volume_usd: string | null; + market_cap_usd: string | null; +} + +const sumUsd = (values: (string | null)[]) => { + const priced = values.filter((v): v is string => v !== null); + if (priced.length === 0) return null; + const micros = priced.reduce( + (sum, v) => sum + BigInt(v.replace(".", "")), + 0n, + ); + return `${micros / 1_000_000n}.${(micros % 1_000_000n).toString().padStart(6, "0")}`; +}; + +// Per-quote sums and USD sums over priced quotes only: raw amounts of +// different quote tokens are never added together. +function aggregates(groups: QuoteGroup[]) { + const byQuote = groups.map((g) => ({ + chain_id: decimal(g.chain_id), + quote_token: hex(g.quote_token, 20), + launch_count: g.launch_count, + trade_count: Number(g.trade_count), + volume: g.volume, + market_cap: g.market_cap, + usd_priced: g.volume_usd !== null, + volume_usd: g.volume_usd, + market_cap_usd: g.market_cap_usd, + })); + const count = (rows: typeof byQuote) => + rows.reduce((n, g) => n + g.launch_count, 0); + const priced = byQuote.filter((g) => g.usd_priced); + return { + launch_count: count(byQuote), + trade_count: byQuote.reduce((n, g) => n + g.trade_count, 0), + by_quote: byQuote, + usd: { + volume: sumUsd(priced.map((g) => g.volume_usd)), + market_cap: sumUsd(priced.map((g) => g.market_cap_usd)), + priced_launch_count: count(priced), + excluded_launch_count: count(byQuote) - count(priced), + }, + }; +} + +function swapDirection(token: bigint, quote: bigint) { + if (token === 0n && quote === 0n) return "zero_fill"; + if (token <= 0n && quote >= 0n) return "buy"; + if (token >= 0n && quote <= 0n) return "sell"; + throw new Error("Invalid indexed swap direction"); +} diff --git a/src/routes/launches/replay.postgres.test.ts b/src/routes/launches/replay.postgres.test.ts new file mode 100644 index 0000000..8274aa5 --- /dev/null +++ b/src/routes/launches/replay.postgres.test.ts @@ -0,0 +1,998 @@ +// Actual-handler replay: a local Postgres is populated by the indexer's own +// migrations, stream grouping, processors and DAO from its emitted local +// anvil chain (evm-contracts 853b608), and every launch route is read +// through the app and checked against the raw logs and the chain state the +// fixture recorded after each block. Skipped unless both are given: +// +// ZERO_SEED_INDEXER_WORKTREE=/path/to/indexer (at INDEXER_COMMIT) +// TEST_PG_CONNECTION_STRING=postgres://...@127.0.0.1:port/postgres +// +// Only loopback Postgres is accepted; the test creates and drops its own +// databases. No RPC, provider or remote database is used. +import { afterAll, beforeAll, describe, expect, spyOn, test } from "bun:test"; +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import postgres from "postgres"; +import { app } from "../../router"; +import { Queries } from "../../queries"; +import { LOCAL_INSTANCES, LOCAL_QUOTES, utf8OrNull } from "./policy"; +import { LaunchQueries } from "./queries"; + +const ROOT = process.env.ZERO_SEED_INDEXER_WORKTREE; +const SERVER = process.env.TEST_PG_CONNECTION_STRING; +// The indexer revision and fixture this replay was written against. +export const INDEXER_COMMIT = "4a2587e5b733fb4f9f5c4dd185abc66493698749"; +export const FIXTURE_SHA256 = + "b818cb5a4d939a67bd91a672f394ff32146edb9557cdf597e02ecad04d9a64d6"; + +const ORDERS = [ + "market_cap", + "volume", + "sold_share", + "trade_count", + "created", +] as const; +const cmpBigint = (a: bigint, b: bigint) => (a < b ? -1 : a > b ? 1 : 0); + +type Hex = `0x${string}`; +type Body = Record; +interface RawLog { + address: Hex; + topics: Hex[]; + data: Hex; + blockNumber: Hex; + transactionHash: Hex; + logIndex: Hex; +} +interface Pool { + label: string; + poolId: Hex; + creatorFees: [string, string]; + launchOwner: Hex; + controller: Hex; + feeAtBlockTime: string; + totalSupply: string; + sinkBalance: string; +} +interface Branch { + blocks: { number: number; timestamp: number }[]; + logs: RawLog[]; + states: { blockNumber: number; pools: Pool[] }[]; +} +interface Launch { + poolId: Hex; + token: Hex; + quote: Hex; + quoteKind: "native" | "erc20"; + tokenIsToken1: boolean; + owner: Hex; + requestedSupply: string; + installedSupply: string; + sinkSupply: string; + liquidity: string; + logoUrl: Hex; + tickSpacing: number; + alignedAskTick: number; + alignedUpperTick: number; +} +interface Fixture { + chainId: number; + addresses: Record; + instances: { + extension: Hex; + periphery: Hex; + extensionRuntimeKeccak: Hex; + peripheryRuntimeKeccak: Hex; + deploymentBlock: number; + }[]; + launches: Record; + installations: Record; + forkPoint: number; + branches: { prefix: Branch; alternate: Branch; canonical: Branch }; +} +interface Dao { + begin(fn: (tx: Dao) => Promise): Promise; + deleteOldBlockNumbers(n: number): Promise; + insertBlock(b: { + number: number; + hash: bigint; + time: Date; + baseFeePerGas: null; + numEvents: number; + }): Promise; + loadDiscoveredAddresses(source: unknown): Promise; +} +interface StreamBlock { + header: { blockNumber: bigint }; + logs: { filterIds: number[] }[]; +} +interface Processor { + address: Hex; + filter: { topics: (Hex | null)[]; strict: boolean }; +} +interface Indexer { + DAO: new (sql: unknown, chainId: bigint) => Dao; + NumericIntegerType: unknown; + parseEvmBlockHeader(block: unknown): { + header: { number: number; hash: bigint; timestamp: number }; + block: unknown; + }; + processEvmBlock( + processors: Processor[], + block: unknown, + n: number, + dao: Dao, + ): Promise; + createLogProcessorsV3(config: Record): Processor[]; + logStreamFilters(processors: Processor[]): unknown[]; + loadKnownAddresses( + filters: unknown[], + load: (source: unknown) => Promise, + ): Promise; + groupLogsByBlock( + logs: RawLog[], + filters: unknown[], + known: unknown, + ): StreamBlock[]; + shift(o: { sql: unknown; path: string }): Promise; + postgres: typeof postgres; +} + +const lower = (a: string) => a.toLowerCase(); +const word = (data: Hex, i: number) => + BigInt(`0x${data.slice(2 + 64 * i, 66 + 64 * i)}`); +const hex32 = (n: bigint) => `0x${n.toString(16).padStart(64, "0")}`; +const signed32 = (n: bigint) => Number(BigInt.asIntN(32, n)); +const addr = (t: Hex) => `0x${t.slice(26)}`; + +// The frozen topics (evm-contracts 853b608, vectors/zero-seed-launch.json). +const VECTORS = JSON.parse( + readFileSync( + resolve(import.meta.dir, "vectors/zero-seed-launch.json"), + "utf8", + ), +) as { abi: Record }> }; +const topicOf = (contract: string, prefix: string) => + Object.entries(VECTORS.abi[contract].events).find(([s]) => + s.startsWith(`${prefix}(`), + )![1]; +const T = { + created: topicOf("ZeroSeedLaunch", "LaunchCreated"), + swapped: topicOf("ZeroSeedLaunch", "LaunchSwapped"), + claimed: topicOf("ZeroSeedLaunch", "CreatorFeesClaimed"), + paid: topicOf("ZeroSeedLaunchPeriphery", "LaunchFeesClaimed"), + owner: topicOf("ZeroSeedLaunchPeriphery", "LaunchOwnerChanged"), +}; + +describe.skipIf(!ROOT || !SERVER)( + "launch routes over the indexer's replayed local chain", + () => { + let ix: Indexer; + let fx: Fixture; + let admin: ReturnType; + const template = `zsl_api_${process.pid}_${Date.now()}`; + const created: string[] = []; + let CHAIN: bigint; + let processors: Processor[]; + + const urlFor = (db: string) => { + const url = new URL(SERVER); + url.pathname = `/${db}`; + return url.toString(); + }; + + beforeAll(async () => { + const url = new URL(SERVER); + if (!["127.0.0.1", "localhost"].includes(url.hostname)) + throw new Error("Only loopback test Postgres is permitted"); + const bytes = readFileSync( + resolve(ROOT, "tests/fixtures/zero-seed-launch/local-chain.json"), + ); + expect(createHash("sha256").update(bytes).digest("hex")).toBe( + FIXTURE_SHA256, + ); + fx = JSON.parse(bytes.toString("utf8")) as Fixture; + CHAIN = BigInt(fx.chainId); + const load = async (path: string) => + (await import(resolve(ROOT, path))) as Record; + const dao = await load("src/_shared/dao.ts"); + const evm = await load("src/evm.ts"); + const v3 = await load("src/evm/logProcessorsV3.ts"); + const stream = await load("src/evm/logStream.ts"); + const shared = await load("src/evm/logProcessorsShared.ts"); + const shiftModule = (await import( + Bun.resolveSync("postgres-shift", ROOT) + )) as { default: Indexer["shift"] }; + const pg = (await import(Bun.resolveSync("postgres", ROOT))) as { + default: typeof postgres; + }; + ix = { + ...(dao as unknown as Pick), + ...(evm as unknown as Pick< + Indexer, + "parseEvmBlockHeader" | "processEvmBlock" + >), + ...(v3 as unknown as Pick), + ...(stream as unknown as Pick< + Indexer, + "groupLogsByBlock" | "loadKnownAddresses" + >), + ...(shared as unknown as Pick), + shift: shiftModule.default, + postgres: pg.default, + }; + const unused = (n: number) => `0x${n.toString(16).padStart(40, "0")}`; + const instance = fx.instances[0]; + processors = ix.createLogProcessorsV3({ + mevCaptureAddress: unused(1), + boostedFeesConcentratedAddress: unused(2), + boostedFeesStableswapAddress: unused(3), + coreAddress: fx.addresses.core, + oracleAddress: unused(4), + incentivesAddress: unused(5), + tokenWrapperFactoryAddress: unused(6), + auctionsAddress: unused(7), + twammAddresses: [], + ordersAddresses: [], + positionsContracts: [], + zeroSeedLaunchPins: [ + { + chainId: CHAIN, + address: instance.extension, + runtimeCodehash: instance.extensionRuntimeKeccak, + periphery: instance.periphery, + core: fx.addresses.core, + deploymentBlock: instance.deploymentBlock, + local: true, + source: "tests/fixtures/zero-seed-launch/local-chain.json", + }, + ], + }); + admin = postgres(SERVER, { max: 1, onnotice: () => {} }); + await admin.unsafe(`CREATE DATABASE ${template}`); + const sql = ix.postgres(urlFor(template), { max: 1, onnotice: () => {} }); + await ix.shift({ sql, path: resolve(ROOT, "migrations") }); + await sql.end(); + }, 300_000); + + afterAll(async () => { + for (const name of [...created, template]) + await admin?.unsafe(`DROP DATABASE IF EXISTS ${name} WITH (FORCE)`); + await admin?.end(); + }, 60_000); + + // ---- the indexer side ---------------------------------------------------- + + let counter = 0; + async function freshDb() { + const name = `${template}_${++counter}`; + await admin.unsafe(`CREATE DATABASE ${name} TEMPLATE ${template}`); + created.push(name); + const sql = ix.postgres(urlFor(name), { + max: 1, + onnotice: () => {}, + types: { + bigint: ix.postgres.BigInt, + numeric: ix.NumericIntegerType as never, + }, + }); + await sql`INSERT INTO indexer_cursor (chain_id, order_key, unique_key, last_updated, fork_counter) + VALUES (${CHAIN.toString()}, 0, NULL, NOW(), 0)`; + return { name, sql, dao: new ix.DAO(sql, CHAIN) }; + } + type Db = Awaited>; + + /** The runtime's per-block transaction, then the cursor head the API reads. */ + async function replay( + db: Db, + branch: Branch, + check?: (state: Branch["states"][number], time: bigint) => Promise, + ) { + // as the stream does: the tokens already indexed, plus those the + // branch creates + const filters = ix.logStreamFilters(processors); + const known = await ix.loadKnownAddresses(filters, (source) => + db.dao.loadDiscoveredAddresses(source), + ); + const blocks = ix.groupLogsByBlock(branch.logs, filters, known); + for (const fixtureBlock of branch.blocks) { + const block = blocks.find( + (b) => Number(b.header.blockNumber) === fixtureBlock.number, + ); + if (block) { + const parsed = ix.parseEvmBlockHeader(block); + await db.dao.begin(async (tx) => { + await tx.deleteOldBlockNumbers(parsed.header.number); + await tx.insertBlock({ + number: parsed.header.number, + hash: parsed.header.hash, + time: new Date(parsed.header.timestamp), + baseFeePerGas: null, + numEvents: block.logs.reduce((n, l) => n + l.filterIds.length, 0), + }); + await ix.processEvmBlock( + processors, + parsed.block, + parsed.header.number, + tx, + ); + }); + } + await setHead(db); + const state = branch.states.find( + (s) => s.blockNumber === fixtureBlock.number, + ); + if (check && state) await check(state, BigInt(fixtureBlock.timestamp)); + } + } + + async function setHead(db: Db) { + await db.sql`UPDATE indexer_cursor SET + head_block_number = b.block_number, head_block_hash = b.block_hash, + head_block_time = b.block_time, last_updated = NOW() + FROM (SELECT * FROM blocks WHERE chain_id = ${CHAIN.toString()} + ORDER BY block_number DESC LIMIT 1) b + WHERE indexer_cursor.chain_id = ${CHAIN.toString()}`; + } + + // ---- the API side -------------------------------------------------------- + + /** Routes the app's query delegate to a local reader over the API's own connection settings. */ + function serve(db: Db, now: () => bigint, quotes = LOCAL_QUOTES) { + const apiSql = postgres(urlFor(db.name), { + max: 1, + fetch_types: false, + onnotice: () => {}, + types: { bigint: postgres.BigInt }, + }); + const reader = new LaunchQueries(apiSql as never, { + localHarness: true, + instances: LOCAL_INSTANCES, + quotes, + maxIndexAgeSeconds: 60, + now, + }); + const spies = [ + spyOn(Queries.prototype, "readZeroSeedList").mockImplementation((i) => + reader.list(i), + ), + spyOn(Queries.prototype, "readZeroSeedDetail").mockImplementation( + (c, p) => reader.detail(c, p), + ), + spyOn(Queries.prototype, "readZeroSeedSwaps").mockImplementation((i) => + reader.swaps(i), + ), + spyOn(Queries.prototype, "readZeroSeedClaims").mockImplementation((i) => + reader.claims(i), + ), + spyOn(Queries.prototype, "readZeroSeedOwners").mockImplementation((i) => + reader.owners(i), + ), + ]; + const get = async (path: string, status = 200) => { + const response = await app.fetch( + new Request(`http://localhost${path}`), + { PG_CONNECTION_STRING: urlFor(db.name) }, + ); + const body = (await response.json()) as never; + if (response.status !== status) + throw new Error( + `${path}: ${response.status} ${JSON.stringify(body)}`, + ); + return body as Body; + }; + const stop = async () => { + spies.forEach((s) => s.mockRestore()); + await apiSql.end(); + }; + return { get, stop }; + } + + const path = (label: string) => + `/launches/${CHAIN}/${fx.launches[label].poolId}`; + const logsOf = ( + branches: Branch[], + topic: Hex, + poolId: Hex, + upTo = Number.MAX_SAFE_INTEGER, + ) => + branches + .flatMap((b) => b.logs) + .filter( + (l) => + l.topics[0] === topic && + l.topics[1] === poolId && + Number(l.blockNumber) <= upTo, + ); + + /** One launch at one block: detail versus the raw LaunchCreated log and the chain state. */ + async function expectLaunch( + get: ReturnType["get"], + pool: Pool, + branches: Branch[], + upTo: number, + ) { + const launch = fx.launches[pool.label]; + const body = await get(path(pool.label)); + const [log] = logsOf(branches, T.created, launch.poolId); + const d = log.data; + expect(body.schema_version).toBe("zero-seed-launch-api/v7"); + expect(body.token.address).toBe(lower(addr(log.topics[2]))); + expect(body.controller).toBe(lower(addr(log.topics[3]))); + expect(body.parameters).toEqual({ + name: hex32(word(d, 5)), + symbol: hex32(word(d, 6)), + supply: word(d, 7).toString(), + quote_token: `0x${word(d, 8).toString(16).padStart(40, "0")}`, + ask_tick: signed32(word(d, 9)).toString(), + upper_tick: signed32(word(d, 10)).toString(), + trading_start: word(d, 11).toString(), + decay_rate_x32: word(d, 12).toString(), + initial_fee: word(d, 13).toString(), + final_fee: word(d, 14).toString(), + salt: hex32(word(d, 15)), + }); + // decoded from the packed words: length byte, then content + const text = (w: bigint) => { + const length = Number(w >> 248n); + return utf8OrNull( + Buffer.from(hex32(w).slice(4, 4 + 2 * length), "hex"), + ); + }; + expect([body.token.name, body.token.symbol, body.token.decimals]).toEqual( + [text(word(d, 5)), text(word(d, 6)), 18], + ); + // logo: null when empty or not valid UTF-8, otherwise exactly as emitted + const logo = Buffer.from(launch.logoUrl.slice(2), "hex"); + expect(body.logo_url).toBe(utf8OrNull(logo)); + expect(body.range).toMatchObject({ + tick_spacing: launch.tickSpacing, + aligned_ask_tick: launch.alignedAskTick, + aligned_upper_tick: launch.alignedUpperTick, + }); + expect(body.pool_key.tick_spacing).toBe(launch.tickSpacing); + expect(body.supply).toEqual({ + requested: pool.totalSupply, + installed: launch.installedSupply, + sink: pool.sinkBalance, + sink_holder: "0x0000000000000000000000000000000000000000", + }); + const is1 = body.launch_token_is_token1 as boolean; + expect(is1).toBe(launch.tokenIsToken1); + expect(body.fee_ledger.launch_token.unclaimed).toBe( + pool.creatorFees[is1 ? 1 : 0], + ); + expect(body.fee_ledger.quote_token.unclaimed).toBe( + pool.creatorFees[is1 ? 0 : 1], + ); + expect([body.owner, body.fee_ledger.holder, body.creator]).toEqual([ + lower(pool.launchOwner), + lower(pool.launchOwner), + lower(fx.installations[pool.label].owner), + ]); + expect(body.controller).toBe(lower(pool.controller)); + expect(body.quote_token.kind).toBe(launch.quoteKind); + // fee rate at the head block equals the contract's feeAt there + expect(body.fee_schedule.fee_rate).toBe(pool.feeAtBlockTime); + expect(body.status).toBe( + body.as_of.block_time < body.trading_start ? "upcoming" : "trading", + ); + expect(body.market.trade_count).toBe(body.fee_ledger.swap_count); + expect(body.market.trade_count).toBe( + logsOf(branches, T.swapped, launch.poolId, upTo).length, + ); + expect(BigInt(body.market.sold)).toBe( + BigInt(launch.installedSupply) - + BigInt(body.principal.pool_reserves.launch_token), + ); + expect(body.market.raised).toBe(body.principal.pool_reserves.quote_token); + return body; + } + + /** Claims: one row per extension claim, never the payout twice. */ + async function expectClaims( + get: ReturnType["get"], + label: string, + branches: Branch[], + ) { + const launch = fx.launches[label]; + const detail = await get(path(label)); + const claims = await get(`${path(label)}/claims?limit=200`); + const ledgerLogs = logsOf(branches, T.claimed, launch.poolId); + const payoutLogs = logsOf(branches, T.paid, launch.poolId); + expect(claims.data.length).toBe(ledgerLogs.length); + expect(claims.data.length).toBe(payoutLogs.length); + expect(claims.data.length).toBe(detail.fee_ledger.claim_count); + const is1 = launch.tokenIsToken1; + const sum = (logs: RawLog[], i: number) => + logs.reduce((n, l) => n + word(l.data, i), 0n).toString(); + const [tokenWord, quoteWord] = is1 ? [1, 0] : [0, 1]; + for (const logs of [ledgerLogs, payoutLogs]) { + expect(sum(logs, tokenWord)).toBe( + detail.fee_ledger.launch_token.claimed, + ); + expect(sum(logs, quoteWord)).toBe( + detail.fee_ledger.quote_token.claimed, + ); + } + expect(claims.totals).toEqual({ + launch_token: detail.fee_ledger.launch_token.claimed, + quote_token: detail.fee_ledger.quote_token.claimed, + }); + // owner and recipient come from the payout of the same transaction + claims.data.forEach((c: Body, i: number) => { + const payout = payoutLogs[i]; + expect(c.event.transaction_hash).toBe(ledgerLogs[i].transactionHash); + expect(c.payout_event_id).not.toBe(c.event.event_id); + expect([c.owner, c.recipient]).toEqual([ + lower(addr(payout.topics[2])), + lower(addr(payout.topics[3])), + ]); + }); + return claims; + } + + // The interface's launch-list ranking, recomputed from served fields: + // descending; for market cap and volume, launches with a USD value + // first by USD, then the rest by whole quote units; ties newest first. + const micros = (usd: string) => BigInt(usd.replace(".", "")); + function rankCompare(key: string, created: string[]) { + const quoteUnits = (l: Body, field: string) => + l.quote_token.decimals === null + ? null + : { raw: BigInt(l.market[field]), decimals: l.quote_token.decimals }; + const cmpBig = (a: bigint, b: bigint) => (a > b ? -1 : a < b ? 1 : 0); + const byUsdThenQuote = (field: string) => (a: Body, b: Body) => { + const [ua, ub] = [a.market[`${field}_usd`], b.market[`${field}_usd`]]; + if ((ua === null) !== (ub === null)) return ua === null ? 1 : -1; + if (ua !== null) return cmpBig(micros(ua), micros(ub)); + const [qa, qb] = [quoteUnits(a, field), quoteUnits(b, field)]; + if (qa === null || qb === null) + return qa === qb ? 0 : qa === null ? 1 : -1; + return cmpBig( + qa.raw * 10n ** BigInt(qb.decimals), + qb.raw * 10n ** BigInt(qa.decimals), + ); + }; + const primary: Record number> = { + market_cap: byUsdThenQuote("market_cap"), + volume: byUsdThenQuote("volume"), + sold_share: (a, b) => + a.market.sold_share < b.market.sold_share + ? 1 + : a.market.sold_share > b.market.sold_share + ? -1 + : 0, + trade_count: (a, b) => b.market.trade_count - a.market.trade_count, + created: () => 0, + }; + return (a: Body, b: Body) => + primary[key](a, b) || + created.indexOf(a.pool_id) - created.indexOf(b.pool_id); + } + + function expectedAggregates(data: Body[]) { + const groups = new Map(); + for (const l of data) { + const k = `${l.chain_id}:${l.quote_token.address}`; + groups.set(k, [...(groups.get(k) ?? []), l]); + } + const sum = (ls: Body[], f: (l: Body) => bigint) => + ls.reduce((n, l) => n + f(l), 0n); + const usd = (v: bigint | null) => + v === null + ? null + : `${v / 1_000_000n}.${(v % 1_000_000n).toString().padStart(6, "0")}`; + const usdSum = (ls: Body[], field: string) => + ls.some((l) => l.market[field] === null) + ? null + : sum(ls, (l) => micros(l.market[field])); + const byQuote = [...groups.entries()] + .sort(([a], [b]) => { + const [ca, qa] = a.split(":"); + const [cb, qb] = b.split(":"); + return ( + cmpBigint(BigInt(ca), BigInt(cb)) || + cmpBigint(BigInt(qa), BigInt(qb)) + ); + }) + .map(([, ls]) => ({ + chain_id: ls[0].chain_id, + quote_token: ls[0].quote_token.address, + launch_count: ls.length, + trade_count: ls.reduce((n, l) => n + l.market.trade_count, 0), + volume: sum(ls, (l) => BigInt(l.market.volume)).toString(), + market_cap: sum(ls, (l) => BigInt(l.market.market_cap)).toString(), + usd_priced: ls[0].market.volume_usd !== null, + volume_usd: usd(usdSum(ls, "volume_usd")), + market_cap_usd: usd(usdSum(ls, "market_cap_usd")), + })); + const priced = data.filter((l) => l.market.volume_usd !== null); + return { + launch_count: data.length, + trade_count: data.reduce((n, l) => n + l.market.trade_count, 0), + by_quote: byQuote, + usd: { + volume: priced.length + ? usd(sum(priced, (l) => micros(l.market.volume_usd))) + : null, + market_cap: priced.length + ? usd(sum(priced, (l) => micros(l.market.market_cap_usd))) + : null, + priced_launch_count: priced.length, + excluded_launch_count: data.length - priced.length, + }, + }; + } + + async function expectOrdersAndAggregates( + get: ReturnType["get"], + label: string, + ) { + const creator = fx.addresses.creator; + for (const filter of [ + "", + "&status=trading", + "&status=upcoming", + `&owner=${creator}`, + `&creator=${creator}`, + ]) { + const created = ( + await get(`/launches?order_by=created&limit=200${filter}`) + ).data.map((l: Body) => l.pool_id); + let aggregates: unknown; + for (const key of ORDERS) { + const full = await get( + `/launches?order_by=${key}&limit=200${filter}`, + ); + const ctx = `${label} ${key}${filter}`; + expect([ctx, full.data.length]).toEqual([ctx, full.total]); + // the order is the interface ranking over the whole filtered set + expect([ctx, full.data.map((l: Body) => l.pool_id)]).toEqual([ + ctx, + [...full.data] + .sort(rankCompare(key, created)) + .map((l: Body) => l.pool_id), + ]); + // pages concatenate to the full order: ordered before offset/limit + const pages: Body[] = []; + let offset: number | null = 0; + while (offset !== null) { + const page = await get( + `/launches?order_by=${key}&limit=2&offset=${offset}${filter}`, + ); + expect(page.aggregates).toEqual(full.aggregates); + pages.push(...page.data); + offset = page.next_offset; + } + expect(pages).toEqual(full.data); + // aggregates cover the filtered set, never one page + expect([ctx, full.aggregates]).toEqual([ + ctx, + expectedAggregates(full.data), + ]); + aggregates ??= full.aggregates; + expect(full.aggregates).toEqual(aggregates); + } + } + // volume and trade count equal the launch's served swaps + const all = await get(`/launches?order_by=created&limit=200`); + for (const l of all.data) { + const swaps = await get( + `/launches/${l.chain_id}/${l.pool_id}/swaps?limit=200`, + ); + expect(swaps.next_cursor).toBeNull(); + expect(swaps.data.length).toBe(l.market.trade_count); + const volume = swaps.data.reduce((n: bigint, s: Body) => { + const d = BigInt(s.quote_token_delta); + return n + (d < 0n ? -d : d); + }, 0n); + expect(l.market.volume).toBe(volume.toString()); + expect(l.market.volume_usd === null).toBe( + l.market.market_cap_usd === null, + ); + } + } + + async function everyResponse(get: ReturnType["get"]) { + const out: Record = { + list: await get(`/launches?order_by=created&limit=200`), + }; + for (const label of ["l1", "l2", "l4", "l5", "l6", "l7", "l8"]) + for (const suffix of [ + "", + "/swaps?limit=200", + "/claims?limit=200", + "/owners?limit=200", + ]) + out[`${label}${suffix}`] = await get(`${path(label)}${suffix}`); + return out; + } + + test("every block: detail equals the raw logs and chain state; claims once; owners; lists; reorg and a second replay are identical", async () => { + const db = await freshDb(); + let time = 0n; + const { get, stop } = serve(db, () => time); + const { prefix, alternate, canonical } = fx.branches; + let pricedList: Body | undefined; + try { + const at = + (branches: Branch[]) => + async (state: Branch["states"][number], blockTime: bigint) => { + time = blockTime; + for (const pool of state.pools) + await expectLaunch(get, pool, branches, state.blockNumber); + }; + await replay(db, prefix, at([prefix])); + await replay(db, alternate, at([prefix, alternate])); + const forked = await get(path("l3")); + expect(forked.creator).toBe(lower(fx.addresses.newOwner)); + // reorg onto the canonical branch: l3 and the alternate transfers vanish + await db.dao.begin((tx) => tx.deleteOldBlockNumbers(fx.forkPoint + 1)); + await replay(db, canonical, at([prefix, canonical])); + for (const suffix of ["", "/swaps", "/claims", "/owners"]) + await get(`${path("l3")}${suffix}`, 404); + for (const label of ["l1", "l2", "l4", "l5", "l6"]) + await expectClaims(get, label, [prefix, canonical]); + + // logos as emitted: empty and invalid UTF-8 are null, the rest raw + const logos = Object.fromEntries( + await Promise.all( + ["l1", "l2", "l4", "l5"].map(async (l) => [ + l, + (await get(path(l))).logo_url, + ]), + ), + ); + expect(logos).toEqual({ + l1: "https://example.invalid/l1.svg", + l2: null, + l4: null, + l5: "ipfs://bafyélogo 🚀", + }); + expect(fx.launches.l4.logoUrl).not.toBe("0x"); + // owners: the full history from the raw logs, creator first, paged + for (const label of ["l1", "l2"]) { + const owners = await get(`${path(label)}/owners`); + const logs = logsOf( + [prefix, canonical], + T.owner, + fx.launches[label].poolId, + ); + expect( + owners.data.map((o: Record) => [ + o.previous_owner, + o.new_owner, + ]), + ).toEqual( + logs.map((l) => [ + BigInt(l.topics[2]) === 0n ? null : lower(addr(l.topics[2])), + lower(addr(l.topics[3])), + ]), + ); + const first = await get(`${path(label)}/owners?limit=1`); + const rest = await get( + `${path(label)}/owners?after_event_id=${first.next_cursor}`, + ); + expect([...first.data, ...rest.data]).toEqual(owners.data); + const detail = await get(path(label)); + expect(detail.owner).toBe(owners.data.at(-1).new_owner); + expect(detail.creator).toBe(owners.data[0].new_owner); + expect(detail.owner).not.toBe(detail.creator); + } + // l1 was transferred twice and then claimed by its new owner + const l1Claims = await get(`${path("l1")}/claims`); + expect( + l1Claims.data.map((c: Record) => c.owner), + ).toContain(lower(fx.addresses.feeRecipient)); + // swaps and claims page without loss or overlap + for (const suffix of ["swaps", "claims"]) { + const all = await get(`${path("l1")}/${suffix}?limit=200`); + const pages = []; + let cursor: string | null = null; + do { + const page = await get( + `${path("l1")}/${suffix}?limit=2${cursor ? `&after_event_id=${cursor}` : ""}`, + ); + pages.push(...page.data); + cursor = page.next_cursor; + } while (cursor); + expect(pages).toEqual(all.data); + } + + // lists: across chains (chainId omitted) equals the chain's own list + const created = await get(`/launches?order_by=created`); + expect( + created.data.map((l: Record) => l.pool_id), + ).toEqual( + ["l8", "l7", "l6", "l5", "l4", "l2", "l1"].map( + (l) => fx.launches[l].poolId, + ), + ); + expect( + await get(`/launches?chainId=${CHAIN}&order_by=created`), + ).toEqual(created); + expect([created.total, created.totals, created.next_offset]).toEqual([ + 7, + { all: 7, trading: 7, upcoming: 0 }, + null, + ]); + expect(created.heads).toEqual([ + { chain_id: CHAIN.toString(), ...created.data[0].as_of }, + ]); + // offset paging + const first = await get(`/launches?order_by=created&limit=3`); + const second = await get( + `/launches?order_by=created&limit=3&offset=${first.next_offset}`, + ); + const third = await get( + `/launches?order_by=created&limit=3&offset=${second.next_offset}`, + ); + expect([ + first.next_offset, + second.next_offset, + third.next_offset, + ]).toEqual([3, 6, null]); + expect([...first.data, ...second.data, ...third.data]).toEqual( + created.data, + ); + // status: before l7/l8's trading start they are upcoming + const l7Start = BigInt(fx.installations.l7.tradingStart); + time = l7Start - 1n; + const upcoming = await get(`/launches?status=upcoming`); + expect( + upcoming.data.map((l: Record) => l.pool_id).sort(), + ).toEqual([fx.launches.l7.poolId, fx.launches.l8.poolId].sort()); + expect( + upcoming.data.every( + (l: Record) => l.status === "upcoming", + ), + ).toBe(true); + expect([upcoming.total, upcoming.totals]).toEqual([ + 2, + { all: 7, trading: 5, upcoming: 2 }, + ]); + const trading = await get(`/launches?status=trading`); + expect(trading.total).toBe(5); + expect((await get(path("l7"))).fee_schedule.phase).toBe( + "before_trading_start", + ); + time = l7Start; + expect((await get(`/launches?status=upcoming`)).total).toBe(0); + expect((await get(path("l7"))).status).toBe("trading"); + // owner filter is the current owner; creator the original one + const owned = await get(`/launches?owner=${fx.addresses.feeRecipient}`); + expect( + owned.data.map((l: Record) => l.pool_id), + ).toEqual([fx.launches.l1.poolId]); + expect( + ( + await get( + `/launches?owner=${BigInt(fx.addresses.creator).toString()}&order_by=created`, + ) + ).data.map((l: Record) => l.pool_id), + ).toEqual(["l7", "l5"].map((l) => fx.launches[l].poolId)); + expect( + ( + await get( + `/launches?creator=${fx.addresses.creator}&order_by=created`, + ) + ).total, + ).toBe(4); + expect((await get(`/launches?owner=0x${"9".repeat(40)}`)).data).toEqual( + [], + ); + // market-cap order: by USD when the quote has a price, the rest after + const byCap = await get(`/launches`); + expect( + byCap.data.every((l: Body) => l.market.market_cap_usd === null), + ).toBe(true); + await db.sql`INSERT INTO erc20_tokens_latest_price (chain_id, token_address, source, "timestamp", value, confidence, valid_until) + VALUES (${CHAIN.toString()}, 0, 'tst', NOW(), 2000, 100, NOW() + INTERVAL '1 hour')`; + const priced = await get(`/launches`); + const native = priced.data.filter( + (l: Body) => l.quote_token.kind === "native", + ); + expect(priced.data.slice(0, native.length)).toEqual(native); + const usd = native.map((l: Body) => Number(l.market.market_cap_usd)); + expect([...usd].sort((a, b) => b - a)).toEqual(usd); + for (const l of native) { + const mc = BigInt(l.market.market_cap); + expect(Number(l.market.market_cap_usd)).toBeCloseTo( + (Number(mc) / 1e18) * 2000, + 0, + ); + } + await expectOrdersAndAggregates(get, "native priced"); + pricedList = await get(`/launches?order_by=volume&limit=200`); + expect(pricedList.aggregates.usd.excluded_launch_count).toBe( + pricedList.data.length - native.length, + ); + await db.sql`DELETE FROM erc20_tokens_latest_price WHERE source = 'tst'`; + await expectOrdersAndAggregates(get, "unpriced"); + // mixed quote decimals: unpriced launches rank by whole quote units + const erc20 = BigInt(LOCAL_QUOTES[0].address).toString(); + await db.sql`INSERT INTO erc20_tokens (chain_id, token_address, token_symbol, token_name, token_decimals, visibility_priority, sort_order) + VALUES (${CHAIN.toString()}, ${erc20}, 'TQ', 'Test quote', 6, 0, 0)`; + await expectOrdersAndAggregates(get, "6-decimal erc20 unpriced"); + // both quotes priced: one USD total, raw amounts still per quote + await db.sql`INSERT INTO erc20_tokens_latest_price (chain_id, token_address, source, "timestamp", value, confidence, valid_until) + VALUES (${CHAIN.toString()}, 0, 'tst', NOW(), 2000, 100, NOW() + INTERVAL '1 hour'), + (${CHAIN.toString()}, ${erc20}, 'tst', NOW(), 0.5, 100, NOW() + INTERVAL '1 hour')`; + await expectOrdersAndAggregates(get, "both priced"); + const mixed = (await get(`/launches?limit=200`)).aggregates; + expect(mixed.by_quote.map((g: Body) => g.usd_priced)).toEqual([ + true, + true, + ]); + expect(mixed.usd.excluded_launch_count).toBe(0); + expect( + micros(mixed.usd.volume) === + micros(mixed.by_quote[0].volume_usd) + + micros(mixed.by_quote[1].volume_usd), + ).toBe(true); + await db.sql`DELETE FROM erc20_tokens_latest_price WHERE source = 'tst'`; + await db.sql`DELETE FROM erc20_tokens WHERE chain_id = ${CHAIN.toString()} AND token_address = ${erc20}`; + // unsupported ERC-20 quotes are screened before paging + await stop(); + const nativeOnly = serve(db, () => time, []); + const page = await nativeOnly.get(`/launches?order_by=created&limit=2`); + expect( + page.data.map((l: Record) => l.pool_id), + ).toEqual(["l5", "l1"].map((l) => fx.launches[l].poolId)); + expect(page.total).toBe(2); + await nativeOnly.get(path("l2"), 404); + await nativeOnly.stop(); + + // a straight second replay into a fresh database serves identical bodies, + // evaluated at the head block + time = BigInt(canonical.blocks.at(-1)!.timestamp); + const reread = serve(db, () => time); + const first1 = await everyResponse(reread.get); + if (process.env.LAUNCH_GOLDEN_DIR) + await Bun.write( + resolve( + process.env.LAUNCH_GOLDEN_DIR, + "zero-seed-launch-api-v7.golden.json", + ), + `${JSON.stringify( + { + source: { + indexer_commit: INDEXER_COMMIT, + fixture_sha256: FIXTURE_SHA256, + evaluated_at: Number(time), + }, + ...first1, + list_by_volume_native_priced: pricedList, + }, + null, + 2, + )}\n`, + ); + await reread.stop(); + const db2 = await freshDb(); + await replay(db2, prefix); + await replay(db2, canonical); + // block heads are identical; restore the same evaluation time + const again = serve(db2, () => time); + expect(await everyResponse(again.get)).toEqual(first1); + // redelivery: re-applying the last blocks changes nothing + await replay(db2, { ...canonical, blocks: canonical.blocks.slice(-3) }); + expect(await everyResponse(again.get)).toEqual(first1); + await again.stop(); + await db2.sql.end(); + + // stale or incoherent heads are 503, naming the chain + const late = serve(db, () => time); + await db.sql`UPDATE indexer_cursor SET last_updated = NOW() - INTERVAL '2 minutes'`; + await late.get(path("l1"), 503); + await late.get(`/launches`, 503); + await late.stop(); + } finally { + await stop().catch(() => {}); + await db.sql.end(); + } + }, 300_000); + }, +); diff --git a/src/routes/launches/routes.test.ts b/src/routes/launches/routes.test.ts new file mode 100644 index 0000000..60943a6 --- /dev/null +++ b/src/routes/launches/routes.test.ts @@ -0,0 +1,110 @@ +import { expect, spyOn, test } from "bun:test"; +import { app } from "../../router"; +import { Queries } from "../../queries"; +import { StatusError } from "../../shared/errors"; +import { LOCAL_INSTANCES, LOCAL_QUOTES } from "./policy"; +import { LaunchQueries } from "./queries"; + +const pool = `0x${"1".repeat(64)}`; +const base = `/launches/31337/${pool}`; +const localEnv = { + PG_CONNECTION_STRING: "postgres://fixture:fixture@127.0.0.1:1/unused", +}; +const request = (path: string, env = {}) => + app.fetch(new Request(`http://localhost${path}`), env); + +test("hosted launch entrypoints stay disabled without database or live pins", async () => { + for (const path of [ + "/launches", + "/launches?chainId=31337", + "/launches?status=upcoming&owner=0x1", + base, + `${base}/swaps`, + `${base}/claims`, + `${base}/owners`, + ]) { + for (const env of [{}, localEnv]) { + const response = await request(path, env); + expect(response.status).toBe(404); + expect(await response.json()).toEqual({ + status: 404, + error: "Launch support is disabled", + }); + } + } +}); + +test("the hosted reader enables no instance and no ERC-20 quote", async () => { + const hosted = new LaunchQueries((() => { + throw new Error("no query may run"); + }) as never); + expect(Reflect.get(hosted, "enabled")).toEqual([]); + expect(Reflect.get(hosted, "quotes")).toEqual([]); + const refused = await hosted + .list({ status: "all", orderBy: "market_cap", offset: 0, limit: 1 }) + .then( + () => undefined, + (error: unknown) => error, + ); + expect(refused).toBeInstanceOf(StatusError); + expect(refused).toMatchObject({ status: 404 }); + // even a harness that passes the reviewed lists is refused when not local + const notLocal = new LaunchQueries((() => {}) as never, { + localHarness: false, + instances: LOCAL_INSTANCES, + quotes: LOCAL_QUOTES, + maxIndexAgeSeconds: 60, + }); + expect(Reflect.get(notLocal, "enabled")).toEqual([]); + expect(Reflect.get(notLocal, "quotes")).toEqual([]); +}); + +test("invalid arguments return 400 naming the parameter", async () => { + for (const [path, parameter] of [ + ["/launches?chainId=-1", "chainId"], + ["/launches?chainId=abc", "chainId"], + ["/launches?limit=0", "limit"], + ["/launches?limit=201", "limit"], + ["/launches?offset=-1", "offset"], + ["/launches?offset=1.5", "offset"], + ["/launches?status=live", "status"], + ["/launches?status=", "status"], + ["/launches?order_by=price", "order_by"], + ["/launches?order_by=sold", "order_by"], + [`/launches?owner=0x1${"0".repeat(40)}`, "owner"], + ["/launches?owner=alice", "owner"], + ["/launches?creator=owner", "creator"], + [`${base}/swaps?after_event_id=-9223372036854775809`, "after_event_id"], + [`${base}/claims?after_event_id=01`, "after_event_id"], + [`${base}/owners?limit=201`, "limit"], + [`/launches/31337/0x1${"0".repeat(64)}`, "poolId"], + ["/launches/31337/NaN", "poolId"], + [`/launches/x/${pool}`, "chainId"], + ] as const) { + const response = await request(path); + expect(response.status).toBe(400); + const body = (await response.json()) as { status: number; error: string }; + expect(body.status).toBe(400); + expect(body.error).toContain(parameter); + } + expect((await request(`${base}/stats`)).status).toBe(404); +}); + +test("stale-index errors retain the established 503 error envelope", async () => { + const stub = spyOn( + Queries.prototype, + "readZeroSeedDetail", + ).mockImplementation(() => { + throw new StatusError(503, "Launch index is stale or has no coherent head"); + }); + try { + const response = await request(base, localEnv); + expect(response.status).toBe(503); + expect(await response.json()).toEqual({ + status: 503, + error: "Launch index is stale or has no coherent head", + }); + } finally { + stub.mockRestore(); + } +}); diff --git a/src/routes/launches/schema.ts b/src/routes/launches/schema.ts new file mode 100644 index 0000000..fa11e81 --- /dev/null +++ b/src/routes/launches/schema.ts @@ -0,0 +1,315 @@ +import { z } from "@hono/zod-openapi"; + +// v7: the final zero-seed launch (evm-contracts 853b608) only. One fee model, +// so the schedule has no discriminator; launches carry their logo, every +// LaunchParameters field, the derived spacing and aligned bounds, a status +// and market data with volume, and the list spans chains with status/owner +// filters, market-cap, volume, sold-share, trade-count and creation order, +// totals and market aggregates. +export const SCHEMA_VERSION = "zero-seed-launch-api/v7" as const; +export const SchemaVersion = z.literal(SCHEMA_VERSION); +const UINT64_MAX = (1n << 64n) - 1n; +const U = z.string().regex(/^(0|[1-9][0-9]*)$/); +const I = z.string().regex(/^(0|-?[1-9][0-9]*)$/); +const Uint64 = U.max(20).refine( + (value) => /^(0|[1-9][0-9]*)$/.test(value) && BigInt(value) <= UINT64_MAX, +); +// A Q0.64 fee rate: every uint64. The fee fraction is value / 2^64, so the +// maximum 2^64 - 1 is just under 100%, never exactly 100%. +const Q64 = Uint64.openapi({ + description: + "Q0.64 fee rate as a canonical decimal uint64 (0 to 18446744073709551615): the fee fraction is value / 2^64", +}); +const Address = z.string().regex(/^0x[0-9a-f]{40}$/); +const Bytes32 = z.string().regex(/^0x[0-9a-f]{64}$/); +const Seconds = z.number().int().nonnegative(); +const Tick = z.number().int(); +export const BlockRef = z.strictObject({ + block_number: U, + block_hash: Bytes32, + block_time: Seconds, +}); +export const ChainHead = BlockRef.extend({ chain_id: U }); +export const EventRef = BlockRef.extend({ + event_id: I, + transaction_index: z.number().int().nonnegative(), + event_index: z.number().int().nonnegative(), + transaction_hash: Bytes32, +}); +// name and symbol are decoded from the canonical LibString.packOne words in +// parameters (length byte, then content); null when the content is not +// valid UTF-8. Untrusted creator input: escape before display. +const LaunchToken = z.strictObject({ + address: Address, + name: z.string().nullable(), + symbol: z.string().nullable(), + decimals: z.literal(18), +}); +// Native ETH is address 0, always token0, 18 decimals, and has no token +// contract, so it has no ERC-20 metadata. ERC-20 metadata is null when the +// token is not in the indexed token list. +const QuoteToken = z.strictObject({ + address: Address, + name: z.string().nullable(), + symbol: z.string().nullable(), + decimals: z.number().int().min(0).max(255).nullable(), + kind: z.enum(["native", "erc20"]), +}); +const PoolKey = z.strictObject({ + core_address: Address, + token0: Address, + token1: Address, + config: Bytes32, + fee: z.literal("0"), + tick_spacing: z.number().int().positive(), + extension: Address, +}); +// LaunchParameters exactly as emitted in LaunchCreated: numbers as exact +// decimal strings, words as 32-byte hex. ask_tick and upper_tick are the +// requested economic ticks; salt is the owner-namespaced salt the extension +// received. +const Parameters = z.strictObject({ + name: Bytes32, + symbol: Bytes32, + supply: U, + quote_token: Address, + ask_tick: I, + upper_tick: I, + trading_start: Uint64, + decay_rate_x32: Uint64, + initial_fee: Q64, + final_fee: Q64, + salt: Bytes32, +}); +// spacing = ceil((upper - ask) / 256); the installed economic bounds are +// ceil(ask / s) * s and floor(upper / s) * s; pool ticks are those bounds, +// negated and swapped when the launch token is token1. +const Range = z.strictObject({ + tick_spacing: z.number().int().positive(), + aligned_ask_tick: Tick, + aligned_upper_tick: Tick, + pool_tick_lower: Tick, + pool_tick_upper: Tick, +}); +// final_fee is the long-run floor the fee approaches; there is no end time. +// fee = final + floor((initial - final) * toFixed(tickToSqrtRatio(-m)) / +// 2^128), m = floor(rate * elapsed / 2^32), initial before and at the start. +export const FeeSchedule = z.strictObject({ + trading_start: Seconds, + initial_fee: Q64, + final_fee: Q64, + decay_rate_x32: Uint64.openapi({ + description: + "decayRateX32: unsigned Q32.32 ticks per second as a canonical decimal uint64; 0 keeps initial_fee", + }), + half_life_seconds: z + .string() + .regex(/^(0|[1-9][0-9]*)\.[0-9]{6}$/) + .nullable() + .openapi({ + description: + "Half-life of the excess over the floor, seconds with 6 decimals (floored); null for rate 0. Display only", + }), + saturation_elapsed_seconds: U.nullable().openapi({ + description: + "floor(381061679028371455 / decay_rate_x32): after this many seconds the fee is exactly final_fee; null for rate 0", + }), + phase: z.enum(["before_trading_start", "decaying", "at_floor", "constant"]), + fee_rate: Q64, + evaluated_at: Seconds, +}); +// Raw launch-token units. requested is LaunchParameters.supply and the +// token's totalSupply; installed went into the position; sink = requested - +// installed was minted to address 0. The sink is not a burn. +const Supply = z.strictObject({ + requested: U, + installed: U, + sink: U, + sink_holder: z.literal("0x0000000000000000000000000000000000000000"), +}); +// USD with exactly 6 decimals, from the indexed quote price. +const Usd = z.string().regex(/^(0|[1-9][0-9]*)\.[0-9]{6}$/); +// Computed from the indexed Core pool state, balances and LaunchSwapped +// events. Raw units; price is raw quote per raw launch token, times 2^128 +// and floored. +const Market = z.strictObject({ + price_tick: Tick, + price_x128: U, + market_cap: U.openapi({ + description: + "floor(price * totalSupply) in raw quote units; totalSupply includes the sink", + }), + market_cap_usd: Usd.nullable().openapi({ + description: + "market_cap / 10^quote decimals * the indexed quote USD price, rounded to 6 decimals; null when the quote has no indexed price or no known decimals", + }), + raised: U.openapi({ + description: "Quote held by the launch pool (buyers' net input)", + }), + sold: U.openapi({ + description: "installed - launch tokens left in the pool", + }), + sold_share: z + .string() + .regex(/^[01]\.[0-9]{18}$/) + .openapi({ description: "sold / installed, 18 decimals, floored" }), + trade_count: z.number().int().nonnegative().openapi({ + description: "LaunchSwapped events of the launch, zero fills included", + }), + volume: U.openapi({ + description: + "Sum of |quote delta| over every LaunchSwapped of the launch, buys and sells, fee-inclusive, in raw quote base units", + }), + volume_usd: Usd.nullable().openapi({ + description: + "volume / 10^quote decimals * the indexed quote USD price, rounded to 6 decimals; null exactly when market_cap_usd is", + }), +}); +export const LaunchSummary = z.strictObject({ + schema_version: SchemaVersion, + chain_id: U, + pool_id: Bytes32, + pool_key: PoolKey, + token: LaunchToken, + quote_token: QuoteToken, + launch_token_is_token1: z.boolean(), + // The locker that forwarded the creation: the instance's periphery. + controller: Address, + // Owner at creation (LaunchOwnerChanged from the zero address). + creator: Address, + // Current owner: holds the unclaimed and future creator fees. + owner: Address, + logo_url: z.string().nullable().openapi({ + description: + "LaunchCreated.logoUrl exactly as emitted; null when empty or not valid UTF-8. Untrusted: never fetched or rewritten here", + }), + parameters: Parameters, + range: Range, + supply: Supply, + trading_start: Seconds, + status: z.enum(["upcoming", "trading"]).openapi({ + description: "upcoming while evaluated_at < trading_start, else trading", + }), + fee_schedule: FeeSchedule, + market: Market, + created: EventRef, + as_of: BlockRef, +}); +const SideAmounts = z.strictObject({ launch_token: U, quote_token: U }); +const LedgerSide = z.strictObject({ accrued: U, claimed: U, unclaimed: U }); +export const LaunchDetail = LaunchSummary.extend({ + principal: z.strictObject({ + position_id: Bytes32, + liquidity: U, + locked: z.literal(true), + withdrawable: z.literal(false), + pool_reserves: SideAmounts, + }), + fee_ledger: z.strictObject({ + holder: Address, + launch_token: LedgerSide, + quote_token: LedgerSide, + swap_count: z.number().int().nonnegative(), + claim_count: z.number().int().nonnegative(), + owner_change_count: z.number().int().positive(), + last_event_id: I, + }), +}); +const Totals = z.strictObject({ + all: z.number().int().nonnegative(), + trading: z.number().int().nonnegative(), + upcoming: z.number().int().nonnegative(), +}); +const Count = z.number().int().nonnegative(); +// One row per (chain, quote token): amounts of different quote tokens are +// never added together. +const QuoteAggregate = z.strictObject({ + chain_id: U, + quote_token: Address, + launch_count: Count, + trade_count: Count, + volume: U.openapi({ description: "Sum of market.volume, raw quote units" }), + market_cap: U.openapi({ + description: "Sum of market.market_cap, raw quote units", + }), + usd_priced: z.boolean().openapi({ + description: "The quote has an indexed USD price and known decimals", + }), + volume_usd: Usd.nullable(), + market_cap_usd: Usd.nullable(), +}); +export const Aggregates = z + .strictObject({ + launch_count: Count, + trade_count: Count, + by_quote: z.array(QuoteAggregate), + usd: z.strictObject({ + volume: Usd.nullable().openapi({ + description: + "Sum of market.volume_usd over priced launches; null when none is priced", + }), + market_cap: Usd.nullable().openapi({ + description: + "Sum of market.market_cap_usd over priced launches; null when none is priced", + }), + priced_launch_count: Count, + excluded_launch_count: Count.openapi({ + description: + "Launches left out of the USD sums because their quote has no indexed price", + }), + }), + }) + .openapi({ + description: + "Over every launch matching all filters (the set total counts), not one page. by_quote is ordered by chain_id, then quote_token", + }); +export const LaunchList = z.strictObject({ + schema_version: SchemaVersion, + data: z.array(LaunchSummary), + // launches matching every filter, and by status matching the others + total: z.number().int().nonnegative(), + totals: Totals, + aggregates: Aggregates, + next_offset: z.number().int().positive().nullable(), + evaluated_at: Seconds, + heads: z.array(ChainHead), +}); +export const Swap = z.strictObject({ + event: EventRef, + forwarding_locker: Address, + direction: z.enum(["buy", "sell", "zero_fill"]), + launch_token_delta: I, + quote_token_delta: I, + fee_rate: Q64, + fee_amount: U, + fee_asset: z.enum(["launch_token", "quote_token"]), +}); +// One claim, keyed on the extension's CreatorFeesClaimed; the periphery's +// LaunchFeesClaimed of the same transaction supplies owner and recipient. +export const Claim = z.strictObject({ + event: EventRef, + payout_event_id: I, + owner: Address, + recipient: Address, + launch_token_amount: U, + quote_token_amount: U, +}); +export const OwnerChange = z.strictObject({ + event: EventRef, + // null for the creation + previous_owner: Address.nullable(), + new_owner: Address, +}); +const PageIdentity = z.strictObject({ + schema_version: SchemaVersion, + chain_id: U, + pool_id: Bytes32, + next_cursor: z.string().nullable(), + as_of: BlockRef, +}); +export const SwapPage = PageIdentity.extend({ data: z.array(Swap) }); +export const ClaimPage = PageIdentity.extend({ + data: z.array(Claim), + totals: SideAmounts, +}); +export const OwnerPage = PageIdentity.extend({ data: z.array(OwnerChange) }); diff --git a/src/routes/launches/vectors/PROVENANCE.md b/src/routes/launches/vectors/PROVENANCE.md new file mode 100644 index 0000000..da1170d --- /dev/null +++ b/src/routes/launches/vectors/PROVENANCE.md @@ -0,0 +1,16 @@ +# Frozen zero-seed launch vectors + +Copied byte for byte from the source freeze of EkuboProtocol/evm-contracts +commit `853b608ec26d4c80bdad6e394cb8ba686e1ae615` (`test/vectors/`). Local +Forge execution and Python oracles, never deployed: untrusted input, not +live-chain evidence. `policy.test.ts` checks these hashes. + +| File | sha256 | +|---|---| +| `zero-seed-launch.json` | `e5444bf6b1f7e422238331b50b64cf0400597bd13421e281615735511274190b` | +| `zero-seed-launch-installation.json` | `5cf44854cbf00abb700936b2e22782c27dac5e68cf892edc8f5aa7090067a555` | +| `zero-seed-launch-events.json` | `24dd5883ce242ec523517c9f38cfd5e8ca29740974aeded5740ac3608e1e7066` | + +ABI file hashes used by `policy.ts` (`SHA256SUMS.json` of the freeze): +`ZeroSeedLaunch.abi.json` `6a131c2d2f70f85a5e2a54395b9d77c4dd5028a7a4bbf632f3d3364ac61e56eb`, +`ZeroSeedLaunchPeriphery.abi.json` `5d05426f8190cb0bcd6a021e7aceb46f468708cb36bd5a5d818548650499c839`. diff --git a/src/routes/launches/vectors/zero-seed-launch-events.json b/src/routes/launches/vectors/zero-seed-launch-events.json new file mode 100644 index 0000000..7e677c4 --- /dev/null +++ b/src/routes/launches/vectors/zero-seed-launch-events.json @@ -0,0 +1,130 @@ +{ + "scope": "Local Forge event fixtures, never deployed", + "LaunchCreated": [ + { + "logo": "", + "topics": [ + "0x0a54c7540832cb23832d30bbf27c5597cfb779d070a1c253a7aee90571c2da4c", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x000000000000000000000000838047be0779c59e69610451ccf3fd71f5fb4a53", + "0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000838047be0779c59e69610451ccf3fd71f5fb4a535100000000000000000000000000000000000000000000000000000080004646000000000000000000000000000000000000000000000000008c8c0000d28bba00000000000000000000000000000000000000000000ed8d74db520e3e09750f095a65726f205365656400000000000000000000000000000000000000000000045a45524f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2d3134ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73764400000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000100b8a78850000000000000000000000000000000000000000000000000ccccccccccccccc00000000000000000000000000000000000000000000000000c49ba5e353f7ceabfb2c1d8ee75c05313d7d3a63c0bb9e04715890c7020bc8528b61929317e98200000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000000" + }, + { + "logo": "https://example.invalid/logo.svg", + "topics": [ + "0x0a54c7540832cb23832d30bbf27c5597cfb779d070a1c253a7aee90571c2da4c", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x000000000000000000000000838047be0779c59e69610451ccf3fd71f5fb4a53", + "0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000838047be0779c59e69610451ccf3fd71f5fb4a535100000000000000000000000000000000000000000000000000000080004646000000000000000000000000000000000000000000000000008c8c0000d28bba00000000000000000000000000000000000000000000ed8d74db520e3e09750f095a65726f205365656400000000000000000000000000000000000000000000045a45524f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2d3134ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73764400000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000100b8a78850000000000000000000000000000000000000000000000000ccccccccccccccc00000000000000000000000000000000000000000000000000c49ba5e353f7ceabfb2c1d8ee75c05313d7d3a63c0bb9e04715890c7020bc8528b61929317e9820000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000002068747470733a2f2f6578616d706c652e696e76616c69642f6c6f676f2e737667" + } + ], + "receipt": [ + { + "emitter": "0x838047Be0779C59E69610451cCf3Fd71F5fB4A53", + "data": "0x0000000000000000000000000000000000000000033b2e3c9fd0803ce7fffe47", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000014aa86c5d3c41765bb24e11bd701" + ] + }, + { + "emitter": "0x838047Be0779C59E69610451cCf3Fd71F5fB4A53", + "data": "0x00000000000000000000000000000000000000000000000000000000000001b9", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + }, + { + "emitter": "0x5100000000000000000000000000000000000000", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000838047be0779c59e69610451ccf3fd71f5fb4a535100000000000000000000000000000000000000000000000000000080004646000000000000000000000000000000000000000000000000008c8c0000d28bba00000000000000000000000000000000000000000000ed8d74db520e3e09750f095a65726f205365656400000000000000000000000000000000000000000000045a45524f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2d3134ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73764400000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000100b8a78850000000000000000000000000000000000000000000000000ccccccccccccccc00000000000000000000000000000000000000000000000000c49ba5e353f7ceabfb2c1d8ee75c05313d7d3a63c0bb9e04715890c7020bc8528b61929317e98200000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000000", + "topics": [ + "0x0a54c7540832cb23832d30bbf27c5597cfb779d070a1c253a7aee90571c2da4c", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x000000000000000000000000838047be0779c59e69610451ccf3fd71f5fb4a53", + "0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a" + ] + }, + { + "emitter": "0xF62849F9A0B5Bf2913b396098F7c7019b51A820a", + "data": "0x", + "topics": [ + "0x478004cf03e8c3b648608ce0259ce479c813aa671a383230ee7763fe5da22391", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000002190d584e30f4a2396c1487aa784428f2068cbe8" + ] + }, + { + "emitter": "0x838047Be0779C59E69610451cCf3Fd71F5fB4A53", + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496", + "0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f" + ] + }, + { + "emitter": "0x5100000000000000000000000000000000000000", + "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000ffffffffffffffffffffffffffffffffffffffffffff3a6eae2c58e969b1150a0000000000000000000000000000000000000000000000000ccccccccccccccc000000000000000000000000000000000000000000000a65f6d53eb058c019df0000000000000000000000000000000000000000000000000000000000000001", + "topics": [ + "0x3e58795f52a8e88efdec2da89ea3798175f8764145ccd7bf5e40633a7d571f6d", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f" + ] + }, + { + "emitter": "0x838047Be0779C59E69610451cCf3Fd71F5fB4A53", + "data": "0x00000000000000000000000000000000000000000000c59151d3a716964eeaf6", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000014aa86c5d3c41765bb24e11bd701", + "0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496" + ] + }, + { + "emitter": "0x5100000000000000000000000000000000000000", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a65f6d53eb058c019df", + "topics": [ + "0xf0ffdfa84530baef2e9f8bbb160545a59bfef8da319fa27aa69e4f3c8f05a41d", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a" + ] + }, + { + "emitter": "0x838047Be0779C59E69610451cCf3Fd71F5fB4A53", + "data": "0x000000000000000000000000000000000000000000000a65f6d53eb058c019df", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000014aa86c5d3c41765bb24e11bd701", + "0x0000000000000000000000002190d584e30f4a2396c1487aa784428f2068cbe8" + ] + }, + { + "emitter": "0xF62849F9A0B5Bf2913b396098F7c7019b51A820a", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a65f6d53eb058c019df", + "topics": [ + "0x908c6b2c19765fe47aef218b4f71ea1a10a9e156d9d5c3500c3a298e01428805", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x0000000000000000000000002190d584e30f4a2396c1487aa784428f2068cbe8", + "0x0000000000000000000000002190d584e30f4a2396c1487aa784428f2068cbe8" + ] + }, + { + "emitter": "0xF62849F9A0B5Bf2913b396098F7c7019b51A820a", + "data": "0x", + "topics": [ + "0x478004cf03e8c3b648608ce0259ce479c813aa671a383230ee7763fe5da22391", + "0xfb5475aaf870f1b1fe76ffcb64a34cd6b1c41d22f723a49abf6bab09e5760c91", + "0x0000000000000000000000002190d584e30f4a2396c1487aa784428f2068cbe8", + "0x000000000000000000000000000000000000000000000000000000000000beef" + ] + } + ] +} diff --git a/src/routes/launches/vectors/zero-seed-launch-installation.json b/src/routes/launches/vectors/zero-seed-launch-installation.json new file mode 100644 index 0000000..e28d1e6 --- /dev/null +++ b/src/routes/launches/vectors/zero-seed-launch-installation.json @@ -0,0 +1,1720 @@ +{ + "version": 2, + "scope": "LOCAL integer vectors for ZeroSeedLaunch.previewInstallation; economic ticks as requested; no deployment", + "supply": "1 <= supply <= 1000000000000000000000000000000 base units (InvalidSupply 0x15ae6727 outside); decimals are always 18", + "ticks": "MIN_TICK <= askTick < upperTick <= MAX_TICK (InvalidTicks 0x1434ed7f outside)", + "spacing_rule": "tickSpacing = ceil((upperTick - askTick) / 256); alignedAskTick = ceil(askTick / tickSpacing) * tickSpacing; alignedUpperTick = floor(upperTick / tickSpacing) * tickSpacing (src/math/launchRange.sol). The aligned range spans at most 256 steps, so its two initialized ticks occupy at most two adjacent tick-bitmap words (bitmapWords) in either token order; the spacing never exceeds 693148 < MAX_TICK_SPACING", + "pool_ticks": "token0 launch: [alignedAskTick, alignedUpperTick], initial tick = lower; token1 launch: [-alignedUpperTick, -alignedAskTick], initial tick = upper", + "token0_liquidity": "floor(supply * lowerFixed * upperFixed / (2**128 * (upperFixed - lowerFixed))), the exact inverse of Core's token0 debit ceil(ceil(liquidity * 2**128 * (upperFixed - lowerFixed) / upperFixed) / lowerFixed); computed on chain as floor(supply * mantissaLower * mantissaUpper / (((upperFixed - lowerFixed) >> shiftLower) << (128 - shiftUpper))) from the compact sqrt ratios (mantissa = low 94 bits, shift = 2 + 32 * top two bits); saturates at 2**128 - 1", + "token1_liquidity": "floor(supply * 2**128 / (upperFixed - lowerFixed)), the shared helper; the exact inverse of ceil(liquidity * (upperFixed - lowerFixed) / 2**128)", + "installed_supply": "the debit above at the installed liquidity; sink = supply - installedSupply is minted to address(0); totalSupply = supply", + "refusals": { + "ZeroLiquidity": "0x10074548", + "LiquidityAboveTickCap(uint128,uint128)": "0x20ea795f", + "tick_cap": "floor((2**128 - 1) / (1 + 2 * floor(88722835 / tickSpacing))); liquidity above it, including the uint128 saturation, is refused rather than capped" + }, + "pins": { + "runtime_templates": { + "ZeroSeedLaunch": { + "bytes": 18366, + "keccak256": "0x707be0d4e2c25c21d6d9aafec5bb58e634118c1edade48d0dc1fd5be5de2624c" + }, + "ZeroSeedLaunchPeriphery": { + "bytes": 6123, + "keccak256": "0xe6c0d086bff1c96e4f0a2e8068022795a0c74f96d15d15cd041cbea2d2e9b529" + }, + "LaunchToken": { + "bytes": 3012, + "keccak256": "0xec01758e39962fca797fc966e3e541ac87c2c72814b9e1ab86d6193597b182b6" + } + }, + "creationCode": { + "ZeroSeedLaunch": { + "bytes": 18884, + "keccak256": "0x6ec3a947c32774eab196724fd1a98c4eb927af430dec7ed1b111be414d85dc20" + }, + "ZeroSeedLaunchPeriphery": { + "bytes": 6343, + "keccak256": "0x4698c93153732a8f4371252ca5af048a7fe5a181dbd6e26ee4e76f2c942abaf2" + }, + "LaunchToken": { + "bytes": 3172, + "keccak256": "0xb92240f5b935a76e949aab04e7e9e4a0a28adc3ff1a89a349c67dcaab13ea432" + } + } + }, + "vectors": [ + { + "label": "fixture 18/18", + "order": "t0", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": -13798330, + "alignedUpperTick": -9210880, + "steps": 255, + "bitmapWords": 2, + "tickLower": -13798330, + "tickUpper": -9210880, + "initialTick": -13798330, + "lowerSqrtRatio": "19827018619021557321624769538", + "upperSqrtRatio": "20005058055867721043010416951", + "lowerFixed": "343219262584225398096347565219905536", + "upperFixed": "3401913497194347663748393335707926528", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1121810267768648385524834", + "installedSupply": "999999999999999999999999508", + "sink": "492", + "debitAtLiquidityPlusOne": "1000000000000000000000000399" + }, + { + "label": "fixture 18/18", + "order": "t1", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": -13798330, + "alignedUpperTick": -9210880, + "steps": 255, + "bitmapWords": 2, + "tickLower": 9210880, + "tickUpper": 13798330, + "initialTick": 13798330, + "lowerSqrtRatio": "39614081718424154951297988133", + "upperSqrtRatio": "39614085829356414111595421918", + "lowerFixed": "34037340847382845064040913858633410805760", + "upperFixed": "337370602003729386149418028072584609792000", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1121810267768648385525007", + "installedSupply": "999999999999999999999999559", + "sink": "441", + "debitAtLiquidityPlusOne": "1000000000000000000000000450" + }, + { + "label": "fixture 18/6", + "order": "t0", + "askTick": -41446500, + "upperTick": -36841300, + "supply": "1000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": -41430970, + "alignedUpperTick": -36843520, + "steps": 255, + "bitmapWords": 2, + "tickLower": -41430970, + "tickUpper": -36843520, + "initialTick": -41430970, + "lowerSqrtRatio": "19807040648528048271455314437", + "upperSqrtRatio": "19807040826424659756276285499", + "lowerFixed": "342943927995065015897478397952", + "upperFixed": "3399184441581161300402487951360", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892132017", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1120910338181752946", + "installedSupply": "999999999999999999488107389", + "sink": "511892611", + "debitAtLiquidityPlusOne": "1000000000000000000380239405" + }, + { + "label": "fixture 18/6", + "order": "t1", + "askTick": -41446500, + "upperTick": -36841300, + "supply": "1000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": -41430970, + "alignedUpperTick": -36843520, + "steps": 255, + "bitmapWords": 2, + "tickLower": 36843520, + "tickUpper": 41430970, + "initialTick": 41430970, + "lowerSqrtRatio": "40075743594324059322585979863", + "upperSqrtRatio": "44189976340101102891421684705", + "lowerFixed": "34064667930597629112500749730287357927075348480", + "upperFixed": "337641462014695448017496846709930090227635847168", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892132017", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1120910338181752946", + "installedSupply": "999999999999999999449009087", + "sink": "550990913", + "debitAtLiquidityPlusOne": "1000000000000000000341141103" + }, + { + "label": "fixture 18/18, supply cap", + "order": "t0", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1000000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": -13798330, + "alignedUpperTick": -9210880, + "steps": 255, + "bitmapWords": 2, + "tickLower": -13798330, + "tickUpper": -9210880, + "initialTick": -13798330, + "lowerSqrtRatio": "19827018619021557321624769538", + "upperSqrtRatio": "20005058055867721043010416951", + "lowerFixed": "343219262584225398096347565219905536", + "upperFixed": "3401913497194347663748393335707926528", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1121810267768648385524834552", + "installedSupply": "999999999999999999999999999560", + "sink": "440", + "debitAtLiquidityPlusOne": "1000000000000000000000000000451" + }, + { + "label": "fixture 18/18, supply cap", + "order": "t1", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1000000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": -13798330, + "alignedUpperTick": -9210880, + "steps": 255, + "bitmapWords": 2, + "tickLower": 9210880, + "tickUpper": 13798330, + "initialTick": 13798330, + "lowerSqrtRatio": "39614081718424154951297988133", + "upperSqrtRatio": "39614085829356414111595421918", + "lowerFixed": "34037340847382845064040913858633410805760", + "upperFixed": "337370602003729386149418028072584609792000", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1121810267768648385525007495", + "installedSupply": "999999999999999999999999999283", + "sink": "717", + "debitAtLiquidityPlusOne": "1000000000000000000000000000174" + }, + { + "label": "fixture 18/18, supply cap + 1", + "order": "t0", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1000000000000000000000000000001", + "error": "InvalidSupply", + "selector": "0x15ae6727" + }, + { + "label": "fixture 18/18, supply cap + 1", + "order": "t1", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1000000000000000000000000000001", + "error": "InvalidSupply", + "selector": "0x15ae6727" + }, + { + "label": "fixture 18/18, supply 0", + "order": "t0", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "0", + "error": "InvalidSupply", + "selector": "0x15ae6727" + }, + { + "label": "fixture 18/18, uint128 max", + "order": "t0", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "340282366920938463463374607431768211455", + "error": "InvalidSupply", + "selector": "0x15ae6727" + }, + { + "label": "fixture 18/18, inverted ticks", + "order": "t0", + "askTick": -9210300, + "upperTick": -13815500, + "supply": "1000000000000000000000000000", + "error": "InvalidTicks", + "selector": "0x1434ed7f" + }, + { + "label": "fixture 18/18, equal ticks", + "order": "t0", + "askTick": -13815500, + "upperTick": -13815500, + "supply": "1000000000000000000000000000", + "error": "InvalidTicks", + "selector": "0x1434ed7f" + }, + { + "label": "below MIN_TICK", + "order": "t0", + "askTick": -88722836, + "upperTick": 0, + "supply": "1000000000000000000000000000", + "error": "InvalidTicks", + "selector": "0x1434ed7f" + }, + { + "label": "above MAX_TICK", + "order": "t0", + "askTick": 0, + "upperTick": 88722836, + "supply": "1000000000000000000000000000", + "error": "InvalidTicks", + "selector": "0x1434ed7f" + }, + { + "label": "low price, 1e30", + "order": "t0", + "askTick": -88080384, + "upperTick": -85983232, + "supply": "1000000000000000000000000000000", + "tickSpacing": 8192, + "alignedAskTick": -88080384, + "alignedUpperTick": -85983232, + "steps": 256, + "bitmapWords": 2, + "tickLower": -88080384, + "tickUpper": -85983232, + "initialTick": -88080384, + "lowerSqrtRatio": "6358821724476877202", + "upperSqrtRatio": "18145426989333890332", + "lowerFixed": "25435286897907508808", + "upperFixed": "72581707957335561328", + "tickCap": "15709448636763698050107317641464762", + "supplyEnvelope": { + "minimum": "8690091540532083688", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "115073586432", + "installedSupply": "999999999991410763432286846442", + "sink": "8589236567713153558", + "debitAtLiquidityPlusOne": "1000000000000100854972818930129" + }, + { + "label": "low price, 1e30", + "order": "t1", + "askTick": -88080384, + "upperTick": -85983232, + "supply": "1000000000000000000000000000000", + "tickSpacing": 8192, + "alignedAskTick": -88080384, + "alignedUpperTick": -85983232, + "steps": 256, + "bitmapWords": 2, + "tickLower": 85983232, + "tickUpper": 88080384, + "initialTick": 88080384, + "lowerSqrtRatio": "64455109368432855965439496557", + "upperSqrtRatio": "73786024109890745434315100291", + "lowerFixed": "1595334313507478198208865611889941678896332009971300433920", + "upperFixed": "4552419231679360084912250521926274578455984483792549052416", + "tickCap": "15709448636763698050107317641464762", + "supplyEnvelope": { + "minimum": "8690091540532083688", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "115073586432", + "installedSupply": "999999999991410763454585671556", + "sink": "8589236545414328444", + "debitAtLiquidityPlusOne": "1000000000000100854995117755244" + }, + { + "label": "low price, two liquidity units", + "order": "t0", + "askTick": -88080384, + "upperTick": -85983232, + "supply": "17380183081064167375", + "tickSpacing": 8192, + "alignedAskTick": -88080384, + "alignedUpperTick": -85983232, + "steps": 256, + "bitmapWords": 2, + "tickLower": -88080384, + "tickUpper": -85983232, + "initialTick": -88080384, + "lowerSqrtRatio": "6358821724476877202", + "upperSqrtRatio": "18145426989333890332", + "lowerFixed": "25435286897907508808", + "upperFixed": "72581707957335561328", + "tickCap": "15709448636763698050107317641464762", + "supplyEnvelope": { + "minimum": "8690091540532083688", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "2", + "installedSupply": "17380183081064167375", + "sink": "0", + "debitAtLiquidityPlusOne": "26070274621596251062" + }, + { + "label": "low price, one unit short", + "order": "t0", + "askTick": -88080384, + "upperTick": -85983232, + "supply": "17380183081064167374", + "tickSpacing": 8192, + "alignedAskTick": -88080384, + "alignedUpperTick": -85983232, + "steps": 256, + "bitmapWords": 2, + "tickLower": -88080384, + "tickUpper": -85983232, + "initialTick": -88080384, + "lowerSqrtRatio": "6358821724476877202", + "upperSqrtRatio": "18145426989333890332", + "lowerFixed": "25435286897907508808", + "upperFixed": "72581707957335561328", + "tickCap": "15709448636763698050107317641464762", + "supplyEnvelope": { + "minimum": "8690091540532083688", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "1", + "installedSupply": "8690091540532083688", + "sink": "8690091540532083686", + "debitAtLiquidityPlusOne": "17380183081064167375" + }, + { + "label": "low price, below one unit", + "order": "t0", + "askTick": -88080384, + "upperTick": -85983232, + "supply": "8690091540532083687", + "tickSpacing": 8192, + "alignedAskTick": -88080384, + "alignedUpperTick": -85983232, + "steps": 256, + "bitmapWords": 2, + "tickLower": -88080384, + "tickUpper": -85983232, + "initialTick": -88080384, + "lowerSqrtRatio": "6358821724476877202", + "upperSqrtRatio": "18145426989333890332", + "lowerFixed": "25435286897907508808", + "upperFixed": "72581707957335561328", + "tickCap": "15709448636763698050107317641464762", + "supplyEnvelope": { + "minimum": "8690091540532083688", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "error": "ZeroLiquidity", + "selector": "0x10074548" + }, + { + "label": "full width, supply cap", + "order": "t0", + "askTick": -88722835, + "upperTick": 88722835, + "supply": "1000000000000000000000000000000", + "tickSpacing": 693148, + "alignedAskTick": -88029796, + "alignedUpperTick": 88029796, + "steps": 254, + "bitmapWords": 1, + "tickLower": -88029796, + "tickUpper": 88029796, + "initialTick": -88029796, + "lowerSqrtRatio": "6521713082187947545", + "upperSqrtRatio": "73427235184772856332486820067", + "lowerFixed": "26086852328751790180", + "upperFixed": "4438714482609126741834905067882300589470816915495961231360", + "tickCap": "1334440654591915542993625911497130241", + "supplyEnvelope": { + "minimum": "13044209498050253036", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "76662368857", + "installedSupply": "999999999987511320520150058769", + "sink": "12488679479849941231", + "debitAtLiquidityPlusOne": "1000000000000555530018200311804" + }, + { + "label": "full width, supply cap", + "order": "t1", + "askTick": -88722835, + "upperTick": 88722835, + "supply": "1000000000000000000000000000000", + "tickSpacing": 693148, + "alignedAskTick": -88029796, + "alignedUpperTick": 88029796, + "steps": 254, + "bitmapWords": 1, + "tickLower": -88029796, + "tickUpper": 88029796, + "initialTick": 88029796, + "lowerSqrtRatio": "6521713082187947545", + "upperSqrtRatio": "73427235184772856332486820067", + "lowerFixed": "26086852328751790180", + "upperFixed": "4438714482609126741834905067882300589470816915495961231360", + "tickCap": "1334440654591915542993625911497130241", + "supplyEnvelope": { + "minimum": "13044209498050253035", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "76662368857", + "installedSupply": "999999999987511320481816572317", + "sink": "12488679518183427683", + "debitAtLiquidityPlusOne": "1000000000000555529979866825352" + }, + { + "label": "full width, 1e27", + "order": "t0", + "askTick": -88722835, + "upperTick": 88722835, + "supply": "1000000000000000000000000000", + "tickSpacing": 693148, + "alignedAskTick": -88029796, + "alignedUpperTick": 88029796, + "steps": 254, + "bitmapWords": 1, + "tickLower": -88029796, + "tickUpper": 88029796, + "initialTick": -88029796, + "lowerSqrtRatio": "6521713082187947545", + "upperSqrtRatio": "73427235184772856332486820067", + "lowerFixed": "26086852328751790180", + "upperFixed": "4438714482609126741834905067882300589470816915495961231360", + "tickCap": "1334440654591915542993625911497130241", + "supplyEnvelope": { + "minimum": "13044209498050253036", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "76662368", + "installedSupply": "999999988808623780691083208", + "sink": "11191376219308916792", + "debitAtLiquidityPlusOne": "1000000001852833278741336243" + }, + { + "label": "full width, 1e27", + "order": "t1", + "askTick": -88722835, + "upperTick": 88722835, + "supply": "1000000000000000000000000000", + "tickSpacing": 693148, + "alignedAskTick": -88029796, + "alignedUpperTick": 88029796, + "steps": 254, + "bitmapWords": 1, + "tickLower": -88029796, + "tickUpper": 88029796, + "initialTick": 88029796, + "lowerSqrtRatio": "6521713082187947545", + "upperSqrtRatio": "73427235184772856332486820067", + "lowerFixed": "26086852328751790180", + "upperFixed": "4438714482609126741834905067882300589470816915495961231360", + "tickCap": "1334440654591915542993625911497130241", + "supplyEnvelope": { + "minimum": "13044209498050253035", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "76662368", + "installedSupply": "999999988808623780652749722", + "sink": "11191376219347250278", + "debitAtLiquidityPlusOne": "1000000001852833278703002757" + }, + { + "label": "full width, supply 1", + "order": "t0", + "askTick": -88722835, + "upperTick": 88722835, + "supply": "1", + "tickSpacing": 693148, + "alignedAskTick": -88029796, + "alignedUpperTick": 88029796, + "steps": 254, + "bitmapWords": 1, + "tickLower": -88029796, + "tickUpper": 88029796, + "initialTick": -88029796, + "lowerSqrtRatio": "6521713082187947545", + "upperSqrtRatio": "73427235184772856332486820067", + "lowerFixed": "26086852328751790180", + "upperFixed": "4438714482609126741834905067882300589470816915495961231360", + "tickCap": "1334440654591915542993625911497130241", + "supplyEnvelope": { + "minimum": "13044209498050253036", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "error": "ZeroLiquidity", + "selector": "0x10074548" + }, + { + "label": "adjacent ticks at the bottom", + "order": "t0", + "askTick": -88722835, + "upperTick": -88722834, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -88722835, + "alignedUpperTick": -88722834, + "steps": 1, + "bitmapWords": 1, + "tickLower": -88722835, + "tickUpper": -88722834, + "initialTick": -88722835, + "lowerSqrtRatio": "4611797791050542631", + "upperSqrtRatio": "4611800096948861682", + "lowerFixed": "18447191164202170524", + "upperFixed": "18447200387795446728", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "9223141579672", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "108422926327411597", + "installedSupply": "999999999999999996344855661603", + "sink": "3655144338397", + "debitAtLiquidityPlusOne": "1000000000000000005567997241275" + }, + { + "label": "adjacent ticks at the bottom", + "order": "t1", + "askTick": -88722835, + "upperTick": -88722834, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -88722835, + "alignedUpperTick": -88722834, + "steps": 1, + "bitmapWords": 1, + "tickLower": 88722834, + "tickUpper": 88722835, + "initialTick": 88722835, + "lowerSqrtRatio": "79227672562865279167584692032", + "upperSqrtRatio": "79227682466138141934206691491", + "lowerFixed": "6276946463590405995231569687814752028850240276668948152320", + "upperFixed": "6276949602062853172742588666607187473671941430179807625216", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "9223141579672", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "108422926327411597", + "installedSupply": "999999999999999996128023363811", + "sink": "3871976636189", + "debitAtLiquidityPlusOne": "1000000000000000005351164943482" + }, + { + "label": "adjacent ticks at the top", + "order": "t0", + "askTick": 88722834, + "upperTick": 88722835, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": 88722834, + "alignedUpperTick": 88722835, + "steps": 1, + "bitmapWords": 1, + "tickLower": 88722834, + "tickUpper": 88722835, + "initialTick": 88722834, + "lowerSqrtRatio": "79227672562865279167584692032", + "upperSqrtRatio": "79227682466138141934206691491", + "lowerFixed": "6276946463590405995231569687814752028850240276668948152320", + "upperFixed": "6276949602062853172742588666607187473671941430179807625216", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "51979", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "adjacent ticks at the top", + "order": "t1", + "askTick": 88722834, + "upperTick": 88722835, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": 88722834, + "alignedUpperTick": 88722835, + "steps": 1, + "bitmapWords": 1, + "tickLower": -88722835, + "tickUpper": -88722834, + "initialTick": -88722834, + "lowerSqrtRatio": "4611797791050542631", + "upperSqrtRatio": "4611800096948861682", + "lowerFixed": "18447191164202170524", + "upperFixed": "18447200387795446728", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "51979", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "adjacent ticks at the top, supply 1", + "order": "t0", + "askTick": 88722834, + "upperTick": 88722835, + "supply": "1", + "tickSpacing": 1, + "alignedAskTick": 88722834, + "alignedUpperTick": 88722835, + "steps": 1, + "bitmapWords": 1, + "tickLower": 88722834, + "tickUpper": 88722835, + "initialTick": 88722834, + "lowerSqrtRatio": "79227672562865279167584692032", + "upperSqrtRatio": "79227682466138141934206691491", + "lowerFixed": "6276946463590405995231569687814752028850240276668948152320", + "upperFixed": "6276949602062853172742588666607187473671941430179807625216", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "51979", + "nonempty": true + }, + "liquidity": "36892603211249009589164678", + "installedSupply": "1", + "sink": "0", + "debitAtLiquidityPlusOne": "2" + }, + { + "label": "adjacent ticks at the top, cap", + "order": "t0", + "askTick": 88722834, + "upperTick": 88722835, + "supply": "1000000000000", + "tickSpacing": 1, + "alignedAskTick": 88722834, + "alignedUpperTick": 88722835, + "steps": 1, + "bitmapWords": 1, + "tickLower": 88722834, + "tickUpper": 88722835, + "initialTick": 88722834, + "lowerSqrtRatio": "79227672562865279167584692032", + "upperSqrtRatio": "79227682466138141934206691491", + "lowerFixed": "6276946463590405995231569687814752028850240276668948152320", + "upperFixed": "6276949602062853172742588666607187473671941430179807625216", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "51979", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "36892603211249009589164678108647352867" + }, + { + "label": "one word wide at spacing 1", + "order": "t0", + "askTick": -13815500, + "upperTick": -13815244, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815244, + "steps": 256, + "bitmapWords": 2, + "tickLower": -13815500, + "tickUpper": -13815244, + "initialTick": -13815500, + "lowerSqrtRatio": "19826847842167416264437938874", + "upperSqrtRatio": "19826850377651757028987077894", + "lowerFixed": "340285338570426986943133710140047360", + "upperFixed": "340328897859719402375886813570007040", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "245443876583013952532725738056", + "nonempty": true + }, + "liquidity": "7813072147042959328981570090", + "installedSupply": "1000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000001" + }, + { + "label": "one word wide at spacing 1", + "order": "t1", + "askTick": -13815500, + "upperTick": -13815244, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815244, + "steps": 256, + "bitmapWords": 2, + "tickLower": 13815244, + "tickUpper": 13815500, + "initialTick": 13815500, + "lowerSqrtRatio": "39614085868187661632152093760", + "upperSqrtRatio": "39614085868777914215468221053", + "lowerFixed": "340235842344027696174984133961348900978688", + "upperFixed": "340279395297400810272991339629943340400640", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "245443876583013952519617503627", + "nonempty": true + }, + "liquidity": "7813072147042959329398836891", + "installedSupply": "1000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000001" + }, + { + "label": "one word wide at spacing 1, supply cap", + "order": "t0", + "askTick": -13815500, + "upperTick": -13815244, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815244, + "steps": 256, + "bitmapWords": 2, + "tickLower": -13815500, + "tickUpper": -13815244, + "initialTick": -13815500, + "lowerSqrtRatio": "19826847842167416264437938874", + "upperSqrtRatio": "19826850377651757028987077894", + "lowerFixed": "340285338570426986943133710140047360", + "upperFixed": "340328897859719402375886813570007040", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "245443876583013952532725738056", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "7813072147042959328981570090179" + }, + { + "label": "one word wide at spacing 1, supply cap", + "order": "t1", + "askTick": -13815500, + "upperTick": -13815244, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815244, + "steps": 256, + "bitmapWords": 2, + "tickLower": 13815244, + "tickUpper": 13815500, + "initialTick": 13815500, + "lowerSqrtRatio": "39614085868187661632152093760", + "upperSqrtRatio": "39614085868777914215468221053", + "lowerFixed": "340235842344027696174984133961348900978688", + "upperFixed": "340279395297400810272991339629943340400640", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "245443876583013952519617503627", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "7813072147042959329398836891643" + }, + { + "label": "first rounded width", + "order": "t0", + "askTick": -13815500, + "upperTick": -13815243, + "supply": "1000000000000000000000000000", + "tickSpacing": 2, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815244, + "steps": 128, + "bitmapWords": 1, + "tickLower": -13815500, + "tickUpper": -13815244, + "initialTick": -13815500, + "lowerSqrtRatio": "19826847842167416264437938874", + "upperSqrtRatio": "19826850377651757028987077894", + "lowerFixed": "340285338570426986943133710140047360", + "upperFixed": "340328897859719402375886813570007040", + "tickCap": "3835341453200165024746725095425", + "supplyEnvelope": { + "minimum": "1", + "maximum": "490887755932439467353941835249", + "nonempty": true + }, + "liquidity": "7813072147042959328981570090", + "installedSupply": "1000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000001" + }, + { + "label": "first rounded width", + "order": "t1", + "askTick": -13815500, + "upperTick": -13815243, + "supply": "1000000000000000000000000000", + "tickSpacing": 2, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815244, + "steps": 128, + "bitmapWords": 1, + "tickLower": 13815244, + "tickUpper": 13815500, + "initialTick": 13815500, + "lowerSqrtRatio": "39614085868187661632152093760", + "upperSqrtRatio": "39614085868777914215468221053", + "lowerFixed": "340235842344027696174984133961348900978688", + "upperFixed": "340279395297400810272991339629943340400640", + "tickCap": "3835341453200165024746725095425", + "supplyEnvelope": { + "minimum": "1", + "maximum": "490887755932439467327725366242", + "nonempty": true + }, + "liquidity": "7813072147042959329398836891", + "installedSupply": "1000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000001" + }, + { + "label": "region 2**96 crossing", + "order": "t0", + "askTick": -44361442, + "upperTick": -44361441, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -44361442, + "alignedUpperTick": -44361441, + "steps": 1, + "bitmapWords": 1, + "tickLower": -44361442, + "tickUpper": -44361441, + "initialTick": -44361442, + "lowerSqrtRatio": "19807038019411659194957474410", + "upperSqrtRatio": "19807040633177772115164400283", + "lowerFixed": "79228152077646636779829897640", + "upperFixed": "79228191691712772083984367616", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "2148", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "465661575212763904543525", + "installedSupply": "999999999999999999999999306", + "sink": "694", + "debitAtLiquidityPlusOne": "1000000000000000000000001453" + }, + { + "label": "region 2**96 crossing", + "order": "t0", + "askTick": -44361442, + "upperTick": -44361440, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -44361442, + "alignedUpperTick": -44361440, + "steps": 2, + "bitmapWords": 1, + "tickLower": -44361442, + "tickUpper": -44361440, + "initialTick": -44361442, + "lowerSqrtRatio": "19807038019411659194957474410", + "upperSqrtRatio": "19807040633177774421007682211", + "lowerFixed": "79228152077646636779829897640", + "upperFixed": "79228231305798714412255674368", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "4295", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "232830845814061502201641833", + "installedSupply": "999999999999999999999999996985", + "sink": "3015", + "debitAtLiquidityPlusOne": "1000000000000000000000000001280" + }, + { + "label": "region 2**96 crossing wide", + "order": "t0", + "askTick": -44361442, + "upperTick": 0, + "supply": "1000000000000000000000000000", + "tickSpacing": 173287, + "alignedAskTick": -44188185, + "alignedUpperTick": 0, + "steps": 255, + "bitmapWords": 2, + "tickLower": -44188185, + "tickUpper": 0, + "initialTick": -44188185, + "lowerSqrtRatio": "19807040633595087861311793454", + "upperSqrtRatio": "39614081261743854815199363072", + "lowerFixed": "86397621618948338744379310080", + "upperFixed": "340282366920938463463374607431768211456", + "tickCap": "332631834722324988722751326912774400", + "supplyEnvelope": { + "minimum": "3938561739", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "253899790408353378", + "installedSupply": "999999999999999996725183603", + "sink": "3274816397", + "debitAtLiquidityPlusOne": "1000000000000000000663745342" + }, + { + "label": "region 2**128 crossing", + "order": "t0", + "askTick": -1, + "upperTick": 1, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -1, + "alignedUpperTick": 1, + "steps": 2, + "bitmapWords": 1, + "tickLower": -1, + "tickUpper": 1, + "initialTick": -1, + "lowerSqrtRatio": "39614071353619282147775793476", + "upperSqrtRatio": "39614081261743857121041795825", + "lowerFixed": "340282196779882608775400081047712432128", + "upperFixed": "340282537062079388641046796912818126848", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "1917669756958261589446310", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "1000000499999924847075404150522817" + }, + { + "label": "region 2**128 crossing", + "order": "t1", + "askTick": -1, + "upperTick": 1, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -1, + "alignedUpperTick": 1, + "steps": 2, + "bitmapWords": 1, + "tickLower": -1, + "tickUpper": 1, + "initialTick": 1, + "lowerSqrtRatio": "39614071353619282147775793476", + "upperSqrtRatio": "39614081261743857121041795825", + "lowerFixed": "340282196779882608775400081047712432128", + "upperFixed": "340282537062079388641046796912818126848", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "1917669756958261589350720", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "1000000499999924847125251163448363" + }, + { + "label": "region 2**160 crossing", + "order": "t0", + "askTick": 44361441, + "upperTick": 44361442, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": 44361441, + "alignedUpperTick": 44361442, + "steps": 1, + "bitmapWords": 1, + "tickLower": 44361441, + "tickUpper": 44361442, + "initialTick": 44361441, + "lowerSqrtRatio": "59421114591338830873580461336", + "upperSqrtRatio": "59421121890309939821076534892", + "lowerFixed": "1461501099102177137331732072520887438988072189952", + "upperFixed": "1461501829852544000734507580892718290576772956160", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "223246168317635", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "region 2**160 crossing", + "order": "t1", + "askTick": 44361441, + "upperTick": 44361442, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": 44361441, + "alignedUpperTick": 44361442, + "steps": 1, + "bitmapWords": 1, + "tickLower": -44361442, + "tickUpper": -44361441, + "initialTick": -44361441, + "lowerSqrtRatio": "19807038019411659194957474410", + "upperSqrtRatio": "19807040633177772115164400283", + "lowerFixed": "79228152077646636779829897640", + "upperFixed": "79228191691712772083984367616", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "223246168317648", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "three regions", + "order": "t0", + "askTick": -44361442, + "upperTick": 44361442, + "supply": "1000000000000000000000000000", + "tickSpacing": 346574, + "alignedAskTick": -44014898, + "alignedUpperTick": 44014898, + "steps": 254, + "bitmapWords": 1, + "tickLower": -44014898, + "tickUpper": 44014898, + "initialTick": -44014898, + "lowerSqrtRatio": "19807040634050251886466666528", + "upperSqrtRatio": "56270000780324829244662726208", + "lowerFixed": "94217280028371943495823261696", + "upperFixed": "1228989939026549719071510155195115008447542722560", + "tickCap": "665914612369742589947895513565104132", + "supplyEnvelope": { + "minimum": "3611676827", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "276879701057981879", + "installedSupply": "999999999999999999201164169", + "sink": "798835831", + "debitAtLiquidityPlusOne": "1000000000000000002812840995" + }, + { + "label": "three regions", + "order": "t1", + "askTick": -44361442, + "upperTick": 44361442, + "supply": "1000000000000000000000000000", + "tickSpacing": 346574, + "alignedAskTick": -44014898, + "alignedUpperTick": 44014898, + "steps": 254, + "bitmapWords": 1, + "tickLower": -44014898, + "tickUpper": 44014898, + "initialTick": 44014898, + "lowerSqrtRatio": "19807040634050251886466666528", + "upperSqrtRatio": "56270000780324829244662726208", + "lowerFixed": "94217280028371943495823261696", + "upperFixed": "1228989939026549719071510155195115008447542722560", + "tickCap": "665914612369742589947895513565104132", + "supplyEnvelope": { + "minimum": "3611676827", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "276879701057981879", + "installedSupply": "999999999999999999193455279", + "sink": "806544721", + "debitAtLiquidityPlusOne": "1000000000000000002805132106" + }, + { + "label": "positive ticks, both bounds rounded", + "order": "t0", + "askTick": 60000000, + "upperTick": 70000000, + "supply": "1", + "tickSpacing": 39063, + "alignedAskTick": 60000768, + "alignedUpperTick": 69961833, + "steps": 255, + "bitmapWords": 2, + "tickLower": 60000768, + "tickUpper": 69961833, + "initialTick": 60000768, + "lowerSqrtRatio": "59421133364447837616263712467", + "upperSqrtRatio": "59422792634974961669204623761", + "lowerFixed": "3637760950140238375968157297076375377496176024616960", + "upperFixed": "529481580862594314452120214967405192950959490094596096", + "tickCap": "74902568109385530148222453760019417", + "supplyEnvelope": { + "minimum": "1", + "maximum": "6958376342586156033918", + "nonempty": true + }, + "liquidity": "10764374391619", + "installedSupply": "1", + "sink": "0", + "debitAtLiquidityPlusOne": "2" + }, + { + "label": "positive ticks, both bounds rounded", + "order": "t1", + "askTick": 60000000, + "upperTick": 70000000, + "supply": "1000000000000000000000000000", + "tickSpacing": 39063, + "alignedAskTick": 60000768, + "alignedUpperTick": 69961833, + "steps": 255, + "bitmapWords": 2, + "tickLower": -69961833, + "tickUpper": -60000768, + "initialTick": -60000768, + "lowerSqrtRatio": "54672387776301789389034", + "upperSqrtRatio": "7957648318868528504910952", + "lowerFixed": "218689551105207157556136", + "upperFixed": "31830593275474114019643808", + "tickCap": "74902568109385530148222453760019417", + "supplyEnvelope": { + "minimum": "1", + "maximum": "6958376342586156033917", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "negative ticks, both bounds rounded", + "order": "t0", + "askTick": -70000000, + "upperTick": -60000000, + "supply": "1000000000000000000000000000", + "tickSpacing": 39063, + "alignedAskTick": -69961833, + "alignedUpperTick": -60000768, + "steps": 255, + "bitmapWords": 2, + "tickLower": -69961833, + "tickUpper": -60000768, + "initialTick": -69961833, + "lowerSqrtRatio": "54672387776301789389034", + "upperSqrtRatio": "7957648318868528504910952", + "lowerFixed": "218689551105207157556136", + "upperFixed": "31830593275474114019643808", + "tickCap": "74902568109385530148222453760019417", + "supplyEnvelope": { + "minimum": "1545316099304756", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "647116794065", + "installedSupply": "999999999999124336682130621", + "sink": "875663317869379", + "debitAtLiquidityPlusOne": "1000000000000669652781435377" + }, + { + "label": "negative ticks, both bounds rounded", + "order": "t1", + "askTick": -70000000, + "upperTick": -60000000, + "supply": "1000000000000000000000000000", + "tickSpacing": 39063, + "alignedAskTick": -69961833, + "alignedUpperTick": -60000768, + "steps": 255, + "bitmapWords": 2, + "tickLower": 60000768, + "tickUpper": 69961833, + "initialTick": 69961833, + "lowerSqrtRatio": "59421133364447837616263712467", + "upperSqrtRatio": "59422792634974961669204623761", + "lowerFixed": "3637760950140238375968157297076375377496176024616960", + "upperFixed": "529481580862594314452120214967405192950959490094596096", + "tickCap": "74902568109385530148222453760019417", + "supplyEnvelope": { + "minimum": "1545316099304756", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "647116794065", + "installedSupply": "999999999999124336682121692", + "sink": "875663317878308", + "debitAtLiquidityPlusOne": "1000000000000669652781426447" + }, + { + "label": "range across zero, both bounds rounded", + "order": "t0", + "askTick": -5000001, + "upperTick": 4999999, + "supply": "1000000000000000000000000000", + "tickSpacing": 39063, + "alignedAskTick": -4961001, + "alignedUpperTick": 4961001, + "steps": 254, + "bitmapWords": 1, + "tickLower": -4961001, + "tickUpper": 4961001, + "initialTick": -4961001, + "lowerSqrtRatio": "21464918182048129249605627937", + "upperSqrtRatio": "39614081312229031735371803891", + "lowerFixed": "28482119491911494236774164116067581952", + "upperFixed": "4065430919570415286197717704106911465472", + "tickCap": "74902568109385530148222453760019417", + "supplyEnvelope": { + "minimum": "12", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "84291969943815295400760046", + "installedSupply": "999999999999999999999999992", + "sink": "8", + "debitAtLiquidityPlusOne": "1000000000000000000000000004" + }, + { + "label": "range across zero, both bounds rounded", + "order": "t1", + "askTick": -5000001, + "upperTick": 4999999, + "supply": "1000000000000000000000000000", + "tickSpacing": 39063, + "alignedAskTick": -4961001, + "alignedUpperTick": 4961001, + "steps": 254, + "bitmapWords": 1, + "tickLower": -4961001, + "tickUpper": 4961001, + "initialTick": 4961001, + "lowerSqrtRatio": "21464918182048129249605627937", + "upperSqrtRatio": "39614081312229031735371803891", + "lowerFixed": "28482119491911494236774164116067581952", + "upperFixed": "4065430919570415286197717704106911465472", + "tickCap": "74902568109385530148222453760019417", + "supplyEnvelope": { + "minimum": "12", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "84291969943815295401053197", + "installedSupply": "999999999999999999999999991", + "sink": "9", + "debitAtLiquidityPlusOne": "1000000000000000000000000002" + }, + { + "label": "supply 1", + "order": "t0", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1", + "tickSpacing": 17990, + "alignedAskTick": -13798330, + "alignedUpperTick": -9210880, + "steps": 255, + "bitmapWords": 2, + "tickLower": -13798330, + "tickUpper": -9210880, + "initialTick": -13798330, + "lowerSqrtRatio": "19827018619021557321624769538", + "upperSqrtRatio": "20005058055867721043010416951", + "lowerFixed": "343219262584225398096347565219905536", + "upperFixed": "3401913497194347663748393335707926528", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "error": "ZeroLiquidity", + "selector": "0x10074548" + }, + { + "label": "supply 1", + "order": "t1", + "askTick": -13815500, + "upperTick": -9210300, + "supply": "1", + "tickSpacing": 17990, + "alignedAskTick": -13798330, + "alignedUpperTick": -9210880, + "steps": 255, + "bitmapWords": 2, + "tickLower": 9210880, + "tickUpper": 13798330, + "initialTick": 13798330, + "lowerSqrtRatio": "39614081718424154951297988133", + "upperSqrtRatio": "39614085829356414111595421918", + "lowerFixed": "34037340847382845064040913858633410805760", + "upperFixed": "337370602003729386149418028072584609792000", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "892", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "error": "ZeroLiquidity", + "selector": "0x10074548" + }, + { + "label": "zero liquidity", + "order": "t0", + "askTick": -80000000, + "upperTick": -75394800, + "supply": "1", + "tickSpacing": 17990, + "alignedAskTick": -79983540, + "alignedUpperTick": -75396090, + "steps": 255, + "bitmapWords": 2, + "tickLower": -79983540, + "tickUpper": -75396090, + "initialTick": -79983540, + "lowerSqrtRatio": "364403974585733748688", + "upperSqrtRatio": "3611891681837818381911", + "lowerFixed": "1457615898342934994752", + "upperFixed": "14447566727351273527644", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "209898408956198260", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "error": "ZeroLiquidity", + "selector": "0x10074548" + }, + { + "label": "above tick cap", + "order": "t0", + "askTick": 80000000, + "upperTick": 84605200, + "supply": "1000000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": 80001530, + "alignedUpperTick": 84588980, + "steps": 255, + "bitmapWords": 2, + "tickLower": 80001530, + "tickUpper": 84588980, + "initialTick": 80001530, + "lowerSqrtRatio": "59674053255057240992775639467", + "upperSqrtRatio": "61928121734155291317938697781", + "lowerFixed": "80157150546117218022817454823280203296917128974654504960", + "upperFixed": "794499965667161131382886968388759023355152141081406078976", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "1", + "maximum": "131686236093764274", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "above tick cap", + "order": "t1", + "askTick": 80000000, + "upperTick": 84605200, + "supply": "1000000000000000000000000000000", + "tickSpacing": 17990, + "alignedAskTick": 80001530, + "alignedUpperTick": 84588980, + "steps": 255, + "bitmapWords": 2, + "tickLower": -84588980, + "tickUpper": -80001530, + "initialTick": -80001530, + "lowerSqrtRatio": "36435523675599763755", + "upperSqrtRatio": "361140860323799023561", + "lowerFixed": "145742094702399055020", + "upperFixed": "1444563441295196094244", + "tickCap": "34500899008510439365646822207418453", + "supplyEnvelope": { + "minimum": "1", + "maximum": "131686236093764274", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "340282366920938463463374607431768211455" + }, + { + "label": "narrow at the fixture", + "order": "t0", + "askTick": -13815500, + "upperTick": -13815400, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815400, + "steps": 100, + "bitmapWords": 2, + "tickLower": -13815500, + "tickUpper": -13815400, + "initialTick": -13815500, + "lowerSqrtRatio": "19826847842167416264437938874", + "upperSqrtRatio": "19826848832552360555918821236", + "lowerFixed": "340285338570426986943133710140047360", + "upperFixed": "340302353254211717712258326192979968", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "95880253489875846689099223903", + "nonempty": true + }, + "liquidity": "20000684666478128866992076598", + "installedSupply": "1000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000001" + }, + { + "label": "narrow at the fixture", + "order": "t1", + "askTick": -13815500, + "upperTick": -13815400, + "supply": "1000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815400, + "steps": 100, + "bitmapWords": 2, + "tickLower": 13815400, + "tickUpper": 13815500, + "initialTick": 13815500, + "lowerSqrtRatio": "39614085868547337807943695629", + "upperSqrtRatio": "39614085868777914215468221053", + "lowerFixed": "340262381761484649161671818375838411259904", + "upperFixed": "340279395297400810272991339629943340400640", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "95880253489875846672648633422", + "nonempty": true + }, + "liquidity": "20000684666478128870423680717", + "installedSupply": "1000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000001" + }, + { + "label": "narrow at the fixture, supply cap", + "order": "t0", + "askTick": -13815500, + "upperTick": -13815400, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815400, + "steps": 100, + "bitmapWords": 2, + "tickLower": -13815500, + "tickUpper": -13815400, + "initialTick": -13815500, + "lowerSqrtRatio": "19826847842167416264437938874", + "upperSqrtRatio": "19826848832552360555918821236", + "lowerFixed": "340285338570426986943133710140047360", + "upperFixed": "340302353254211717712258326192979968", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "95880253489875846689099223903", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "20000684666478128866992076598552" + }, + { + "label": "narrow at the fixture, supply cap", + "order": "t1", + "askTick": -13815500, + "upperTick": -13815400, + "supply": "1000000000000000000000000000000", + "tickSpacing": 1, + "alignedAskTick": -13815500, + "alignedUpperTick": -13815400, + "steps": 100, + "bitmapWords": 2, + "tickLower": 13815400, + "tickUpper": 13815500, + "initialTick": 13815500, + "lowerSqrtRatio": "39614085868547337807943695629", + "upperSqrtRatio": "39614085868777914215468221053", + "lowerFixed": "340262381761484649161671818375838411259904", + "upperFixed": "340279395297400810272991339629943340400640", + "tickCap": "1917670715792995950086461153688", + "supplyEnvelope": { + "minimum": "1", + "maximum": "95880253489875846672648633422", + "nonempty": true + }, + "error": "LiquidityAboveTickCap", + "selector": "0x20ea795f", + "liquidity": "20000684666478128870423680717318" + }, + { + "label": "ten percent wide at the fixture, supply cap", + "order": "t0", + "askTick": -13815500, + "upperTick": -13720200, + "supply": "1000000000000000000000000000000", + "tickSpacing": 373, + "alignedAskTick": -13815174, + "alignedUpperTick": -13720432, + "steps": 254, + "bitmapWords": 2, + "tickLower": -13815174, + "tickUpper": -13720432, + "initialTick": -13815174, + "lowerSqrtRatio": "19826851071004761957890969158", + "upperSqrtRatio": "19827812093588065585625405455", + "lowerFixed": "340340809573642414251959237650415616", + "upperFixed": "356851051837668481282209112091787264", + "tickCap": "715292168628805430581480072377462", + "supplyEnvelope": { + "minimum": "47", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "21617631916800636468600113422", + "installedSupply": "1000000000000000000000000000000", + "sink": "0", + "debitAtLiquidityPlusOne": "1000000000000000000000000000046" + }, + { + "label": "ten percent wide at the fixture, supply cap", + "order": "t1", + "askTick": -13815500, + "upperTick": -13720200, + "supply": "1000000000000000000000000000000", + "tickSpacing": 373, + "alignedAskTick": -13815174, + "alignedUpperTick": -13720432, + "steps": 254, + "bitmapWords": 2, + "tickLower": 13720432, + "tickUpper": 13815174, + "initialTick": 13815174, + "lowerSqrtRatio": "39614085654696434799085671354", + "upperSqrtRatio": "39614085868026277594831988382", + "lowerFixed": "324482970250540297643246454993782837346304", + "upperFixed": "340223934303891592275024797922651900215296", + "tickCap": "715292168628805430581480072377462", + "supplyEnvelope": { + "minimum": "47", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "21617631916800636468567531274", + "installedSupply": "999999999999999999999999999957", + "sink": "43", + "debitAtLiquidityPlusOne": "1000000000000000000000000000004" + }, + { + "label": "two times wide at the fixture, supply cap", + "order": "t0", + "askTick": -13815500, + "upperTick": -13122400, + "supply": "1000000000000000000000000000000", + "tickSpacing": 2708, + "alignedAskTick": -13813508, + "alignedUpperTick": -13122968, + "steps": 255, + "bitmapWords": 2, + "tickLower": -13813508, + "tickUpper": -13122968, + "initialTick": -13813508, + "lowerSqrtRatio": "19826867579970088338149538588", + "upperSqrtRatio": "19835043639045498244486435319", + "lowerFixed": "340624431438312818958422140031860736", + "upperFixed": "481088056794511001004000611129098240", + "tickCap": "5193010009933896919794506194877961", + "supplyEnvelope": { + "minimum": "292", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "3428443934989539259216457645", + "installedSupply": "999999999999999999999999999964", + "sink": "36", + "debitAtLiquidityPlusOne": "1000000000000000000000000000255" + }, + { + "label": "two times wide at the fixture, supply cap", + "order": "t1", + "askTick": -13815500, + "upperTick": -13122400, + "supply": "1000000000000000000000000000000", + "tickSpacing": 2708, + "alignedAskTick": -13813508, + "alignedUpperTick": -13122968, + "steps": 255, + "bitmapWords": 2, + "tickLower": 13122968, + "tickUpper": 13813508, + "initialTick": 13813508, + "lowerSqrtRatio": "39614084519061895971356284982", + "upperSqrtRatio": "39614085864187004001293752539", + "lowerFixed": "240687931454459110649981462574315073437696", + "upperFixed": "339940645914255788171351607558895141126144", + "tickCap": "5193010009933896919794506194877961", + "supplyEnvelope": { + "minimum": "292", + "maximum": "1000000000000000000000000000000", + "nonempty": true + }, + "liquidity": "3428443934989539259217557666", + "installedSupply": "999999999999999999999999999931", + "sink": "69", + "debitAtLiquidityPlusOne": "1000000000000000000000000000223" + } + ] +} diff --git a/src/routes/launches/vectors/zero-seed-launch.json b/src/routes/launches/vectors/zero-seed-launch.json new file mode 100644 index 0000000..1b4030f --- /dev/null +++ b/src/routes/launches/vectors/zero-seed-launch.json @@ -0,0 +1,1956 @@ +{ + "version": 8, + "fixture": { + "core": "Locally compiled src/Core.sol deployed at the test's canonical Core address; no fork or live-chain validation", + "router": "Locally compiled test/LaunchTestRouter.sol; standard-ABI single-hop forwarding and settlement, with snapshot/revert quotes in the test harness; no deployed-router bytecode fixture", + "supply_requested": "1000000000000000000000000000", + "tick_spacing": 17990, + "width_ticks": 4605200, + "ask_tick_18_18": -13815500, + "ask_tick_18_6": -41446500, + "trading_start": 1000, + "fee_initial_q64": "922337203685477580", + "fee_final_q64": "55340232221128654", + "max_creator_fee_q64": "18446744073709551615", + "creator_fee_range": "every uint64 0..18446744073709551615 inclusive for initialFee and finalFee (Q0.64; 2**64 - 1 is just under 100%, never exactly 100%); finalFee <= initialFee, else InvalidFeeSchedule; exactly 100% = 2**64 is not a uint64 and fails ABI decoding with empty revert data; see creator_fee_range", + "label": "LOCAL FIXTURE VECTORS - not live evidence; numeric start margin is a local-reference proposal, not a live parameter; the creator fee ceiling is the uint64 maximum", + "quote_18": "t0 order: plain 18-decimal test ERC-20 selected per launch at the top of the address space. t1 order: native ETH, address(0), the reference Base configuration; always token0, no code, no decimals(), no approvals.", + "quote_6": "plain 6-decimal solady ERC-20 (DecimalsToken), selected per launch for math vectors only", + "fee_decay_rates_x32": [ + "68913100933", + "9923486534471" + ], + "fee_decay_rate_x32_default": "68913100933", + "fee_decay_rate_encoding": "decayRateX32: uint64, unsigned Q32.32 ticks per second (2**32 = 1 tick/s). Any value is accepted; 0 is a flat fee. Half-life in seconds of the excess over finalFee = 2 * ln(2) / ln(1.000001) * 2**32 / decayRateX32 = 1386295.05426695565 * 2**32 / decayRateX32. rate for a half-life H: floor(1386295.05426695565... * 2**32 / H), computed with exact high-precision arithmetic (not binary floating point).", + "fee_schedule": "initialFee for t <= 0 or decayRateX32 == 0; finalFee for t > MAX_DECAY_PRODUCT / decayRateX32 (integer division; MAX_DECAY_PRODUCT = (88722835 + 1) * 2**32 - 1 = 381061679028371455); otherwise m = floor(decayRateX32 * t / 2**32) and fee = finalFee + floor((initialFee - finalFee) * R / 2**128) with R = toFixed(tickToSqrtRatio(-m)), the compact (94-bit mantissa, rounded down) sqrt ratio of src/math/ticks.sol as a 64.128 integer. t = block timestamp - tradingStart in whole seconds. The operation order is normative; the saturation check must precede the helper call." + }, + "create": [ + { + "order": "t0", + "dec": "18/18", + "ask": "-13815500", + "upper": "-9210300", + "spacing": "17990", + "alignedAsk": "-13798330", + "alignedUpper": "-9210880", + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999508", + "liquidity": "1121810267768648385524834", + "tickLower": "-13798330", + "tickUpper": "-9210880", + "initialTick": "-13798330", + "withdrawable": "999999999999999999999999507" + }, + { + "order": "t0", + "dec": "18/6", + "ask": "-41446500", + "upper": "-36841300", + "spacing": "17990", + "alignedAsk": "-41430970", + "alignedUpper": "-36843520", + "requested": "1000000000000000000000000000", + "installed": "999999999999999999488107389", + "liquidity": "1120910338181752946", + "tickLower": "-41430970", + "tickUpper": "-36843520", + "initialTick": "-41430970", + "withdrawable": "999999999999999999488107388" + }, + { + "order": "t1", + "dec": "18/18", + "ask": "-13815500", + "upper": "-9210300", + "spacing": "17990", + "alignedAsk": "-13798330", + "alignedUpper": "-9210880", + "requested": "1000000000000000000000000000", + "installed": "999999999999999999999999559", + "liquidity": "1121810267768648385525007", + "tickLower": "9210880", + "tickUpper": "13798330", + "initialTick": "13798330", + "withdrawable": "999999999999999999999999558" + }, + { + "order": "t1", + "dec": "18/6", + "ask": "-41446500", + "upper": "-36841300", + "spacing": "17990", + "alignedAsk": "-41430970", + "alignedUpper": "-36843520", + "requested": "1000000000000000000000000000", + "installed": "999999999999999999449009087", + "liquidity": "1120910338181752946", + "tickLower": "36843520", + "tickUpper": "41430970", + "initialTick": "41430970", + "withdrawable": "999999999999999999449009086" + } + ], + "installation": { + "reference": "zero-seed-launch-installation.json", + "oracle": "zero-seed-launch-installation.py" + }, + "trade": [ + { + "order": "t0", + "dec": "18/18", + "quoteIn": "1000000000000000000", + "gross": "982091443427432213916824", + "fee": "49104572171371610653250", + "net": "932986871256060603263574", + "decimals": "18/18", + "step": "buyExactIn" + }, + { + "order": "t0", + "dec": "18/18", + "tokenOut": "932986871256060603263574", + "calcQuote": "951638594087469002", + "fee": "50086241794077316", + "paid": "1001724835881546318", + "decimals": "18/18", + "step": "buyExactOut" + }, + { + "order": "t0", + "dec": "18/18", + "tokenIn": "932986871256060603263574", + "quoteOut": "904056664383095550", + "decimals": "18/18", + "step": "sellExactIn" + }, + { + "order": "t0", + "dec": "18/18", + "leftHeld": "0", + "principalQuote": "49958055259709451", + "principalToken": "999950895427828628389346150", + "decimals": "18/18", + "step": "reverse" + }, + { + "order": "t0", + "dec": "18/18", + "token": "108", + "quote": "2", + "decimals": "18/18", + "step": "dust" + }, + { + "order": "t0", + "dec": "18/18", + "requested": "999950896427828628389346150", + "got": "999950895427828628389346150", + "principalToken": "0", + "principalQuote": "10083609766202278612140", + "decimals": "18/18", + "step": "exhaust" + }, + { + "order": "t0", + "dec": "18/18", + "positionTokenBefore": "999950895427828628389346150", + "delivered": "999950895427828628389346150", + "residueToken": "0", + "decimals": "18/18", + "step": "upperResidue" + }, + { + "order": "t0", + "dec": "18/18", + "token": "108", + "quote": "2", + "decimals": "18/18", + "step": "dustExhausted" + }, + { + "order": "t0", + "dec": "18/6", + "quoteIn": "1000000", + "gross": "983667637211529436923507", + "fee": "49183381860576471803516", + "net": "934484255350952965119991", + "decimals": "18/6", + "step": "buyExactIn" + }, + { + "order": "t0", + "dec": "18/6", + "tokenOut": "934484255350952965119991", + "calcQuote": "951642", + "fee": "50087", + "paid": "1001729", + "decimals": "18/6", + "step": "buyExactOut" + }, + { + "order": "t0", + "dec": "18/6", + "tokenIn": "934484255350952965119991", + "quoteOut": "904058", + "decimals": "18/6", + "step": "sellExactIn" + }, + { + "order": "t0", + "dec": "18/6", + "leftHeld": "0", + "principalQuote": "49957", + "principalToken": "999950816618139422912052817", + "decimals": "18/6", + "step": "reverse" + }, + { + "order": "t0", + "dec": "18/6", + "token": "104251056", + "quote": "2", + "decimals": "18/6", + "step": "dust" + }, + { + "order": "t0", + "dec": "18/6", + "requested": "999950817618139422912052817", + "got": "999950816618139422912052817", + "principalToken": "0", + "principalQuote": "10067437871", + "decimals": "18/6", + "step": "exhaust" + }, + { + "order": "t0", + "dec": "18/6", + "positionTokenBefore": "999950816618139422912052817", + "delivered": "999950816618139422912052817", + "residueToken": "0", + "decimals": "18/6", + "step": "upperResidue" + }, + { + "order": "t0", + "dec": "18/6", + "token": "104251056", + "quote": "2", + "decimals": "18/6", + "step": "dustExhausted" + }, + { + "order": "t1", + "dec": "18/18", + "quoteIn": "1000000000000000000", + "gross": "982091443427432213710037", + "fee": "49104572171371610642911", + "net": "932986871256060603067126", + "decimals": "18/18", + "step": "buyExactIn" + }, + { + "order": "t1", + "dec": "18/18", + "tokenOut": "932986871256060603067126", + "calcQuote": "951638594087469001", + "fee": "50086241794077316", + "paid": "1001724835881546317", + "decimals": "18/18", + "step": "buyExactOut" + }, + { + "order": "t1", + "dec": "18/18", + "tokenIn": "932986871256060603067126", + "quoteOut": "904056664383095550", + "decimals": "18/18", + "step": "sellExactIn" + }, + { + "order": "t1", + "dec": "18/18", + "leftHeld": "0", + "principalQuote": "49958055259709452", + "principalToken": "999950895427828628388961338", + "decimals": "18/18", + "step": "reverse" + }, + { + "order": "t1", + "dec": "18/18", + "token": "395310", + "quote": "2", + "decimals": "18/18", + "step": "dust" + }, + { + "order": "t1", + "dec": "18/18", + "requested": "999950896427828628388961338", + "got": "999950895427828628388961338", + "principalToken": "0", + "principalQuote": "10083609766202278612147", + "decimals": "18/18", + "step": "exhaust" + }, + { + "order": "t1", + "dec": "18/18", + "positionTokenBefore": "999950895427828628388961338", + "delivered": "999950895427828628388961338", + "residueToken": "0", + "decimals": "18/18", + "step": "upperResidue" + }, + { + "order": "t1", + "dec": "18/18", + "token": "395310", + "quote": "2", + "decimals": "18/18", + "step": "dustExhausted" + }, + { + "order": "t1", + "dec": "18/6", + "quoteIn": "1000000", + "gross": "983667120985587257409989", + "fee": "49183356049279362827840", + "net": "934483764936307894582149", + "decimals": "18/6", + "step": "buyExactIn" + }, + { + "order": "t1", + "dec": "18/6", + "tokenOut": "934483764936307894582149", + "calcQuote": "951641", + "fee": "50087", + "paid": "1001728", + "decimals": "18/6", + "step": "buyExactOut" + }, + { + "order": "t1", + "dec": "18/6", + "tokenIn": "934483764936307894582149", + "quoteOut": "904058", + "decimals": "18/6", + "step": "sellExactIn" + }, + { + "order": "t1", + "dec": "18/6", + "leftHeld": "0", + "principalQuote": "49957", + "principalToken": "999950816643950720086181245", + "decimals": "18/6", + "step": "reverse" + }, + { + "order": "t1", + "dec": "18/6", + "token": "2", + "quote": "3", + "decimals": "18/6", + "step": "dust" + }, + { + "order": "t1", + "dec": "18/6", + "requested": "999950817643950720086181245", + "got": "999950816643950720086181245", + "principalToken": "0", + "principalQuote": "10067437871", + "decimals": "18/6", + "step": "exhaust" + }, + { + "order": "t1", + "dec": "18/6", + "positionTokenBefore": "999950816643950720086181245", + "delivered": "999950816643950720086181245", + "residueToken": "0", + "decimals": "18/6", + "step": "upperResidue" + }, + { + "order": "t1", + "dec": "18/6", + "token": "2", + "quote": "3", + "decimals": "18/6", + "step": "dustExhausted" + } + ], + "fee": [ + { + "decayRateX32": "68913100933", + "t_minus_start": "-1", + "tick_magnitude": null, + "fee_q64": "922337203685477580" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "0", + "tick_magnitude": null, + "fee_q64": "922337203685477580" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "1", + "tick_magnitude": "16", + "fee_q64": "922330267740917652" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "10", + "tick_magnitude": "160", + "fee_q64": "922267846736753839" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "60", + "tick_magnitude": "962", + "fee_q64": "921920278629180106" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "600", + "tick_magnitude": "9627", + "fee_q64": "918173943809149156" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "1800", + "tick_magnitude": "28881", + "fee_q64": "909907303121253143" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "3600", + "tick_magnitude": "57762", + "fee_q64": "897655606672062181" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "43200", + "tick_magnitude": "693147", + "fee_q64": "668399831593786699" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "86399", + "tick_magnitude": "1386279", + "fee_q64": "488842197715736884" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "86400", + "tick_magnitude": "1386295", + "fee_q64": "488838729715618946" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "86401", + "tick_magnitude": "1386311", + "fee_q64": "488835261743244884" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "172800", + "tick_magnitude": "2772590", + "fee_q64": "272089486849531874" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "604800", + "tick_magnitude": "9704065", + "fee_q64": "62113647347197278" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "2592000", + "tick_magnitude": "41588851", + "fee_q64": "55340233028582759" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "5529596", + "tick_magnitude": "88722819", + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "5529597", + "tick_magnitude": "88722835", + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "5529598", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "18446744073709551615", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "68913100933", + "t_minus_start": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "-1", + "tick_magnitude": null, + "fee_q64": "922337203685477580" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "0", + "tick_magnitude": null, + "fee_q64": "922337203685477580" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "1", + "tick_magnitude": "2310", + "fee_q64": "921336400758785753" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "10", + "tick_magnitude": "23104", + "fee_q64": "912379287313991670" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "60", + "tick_magnitude": "138629", + "fee_q64": "864277214588907100" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "600", + "tick_magnitude": "1386295", + "fee_q64": "488838729715618946" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "1800", + "tick_magnitude": "4158885", + "fee_q64": "163714862475909380" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "3600", + "tick_magnitude": "8317770", + "fee_q64": "68887062105693473" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "43200", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "86399", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "86400", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "86401", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "172800", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "604800", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "2592000", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "38398", + "tick_magnitude": "88718262", + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "38399", + "tick_magnitude": "88720572", + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "38400", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "18446744073709551615", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + }, + { + "decayRateX32": "9923486534471", + "t_minus_start": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "tick_magnitude": null, + "fee_q64": "55340232221128654" + } + ], + "router": [ + { + "order": "t0", + "paid": "1000000000000000000", + "got": "932986871256060603263574" + }, + { + "order": "t1", + "paid": "1000000000000000000", + "got": "932986871256060603067126" + } + ], + "gas": [ + { + "order": "t0", + "create": "1145023", + "firstBuy": "102296", + "secondBuy": "34078", + "sell": "34167", + "claim": "70066" + }, + { + "order": "t1", + "create": "1104007", + "firstBuy": "84187", + "secondBuy": "34686", + "sell": "38502", + "claim": "79588" + } + ], + "other": [ + { + "raw": "VEC|recapture|t0|quoteIn=10e18|netOfFee=9256308150479412625085330|afterClaim=9743482263662539604908183" + }, + { + "raw": "VEC|dust|t0|quoteIn=1|net=933793|fee=49148" + } + ], + "gas_note": "In-test warm gas, t0 on the plain 18-decimal test ERC-20 quote and t1 on native ETH, through the periphery (create, claim) and the forwarding test locker (swaps), as logged by test_gas_vectors at this revision (forge 1.8.3, solc 0.8.33, via_ir, optimizer 9999999, evm osaka).", + "residue_metrics": { + "definitions": { + "core_unbooked_dust": "Per token: Core balance - position amount (rounded down) - creator fee ledger, accumulated over all swaps; raw units of that token. Unowned: not creator principal, not creator fees, unreachable by claims.", + "upper_bound_residue": "Raw launch-token units the position held before the exhausting buy that the buy did not deliver when it stopped at the upper bound. Becomes Core unbooked dust: dust_after.token = dust_before.token + residue (asserted)." + }, + "scenarios": [ + { + "order": "t0", + "decimals": "18/18", + "position_token_before_exhaust": "999950895427828628389346150", + "delivered_raw_token": "999950895427828628389346150", + "upper_residue_raw_token": "0", + "core_dust_before_exhaust": { + "raw_token": "108", + "raw_quote": "2" + }, + "core_dust_after_exhaust": { + "raw_token": "108", + "raw_quote": "2" + } + }, + { + "order": "t0", + "decimals": "18/6", + "position_token_before_exhaust": "999950816618139422912052817", + "delivered_raw_token": "999950816618139422912052817", + "upper_residue_raw_token": "0", + "core_dust_before_exhaust": { + "raw_token": "104251056", + "raw_quote": "2" + }, + "core_dust_after_exhaust": { + "raw_token": "104251056", + "raw_quote": "2" + } + }, + { + "order": "t1", + "decimals": "18/18", + "position_token_before_exhaust": "999950895427828628388961338", + "delivered_raw_token": "999950895427828628388961338", + "upper_residue_raw_token": "0", + "core_dust_before_exhaust": { + "raw_token": "395310", + "raw_quote": "2" + }, + "core_dust_after_exhaust": { + "raw_token": "395310", + "raw_quote": "2" + } + }, + { + "order": "t1", + "decimals": "18/6", + "position_token_before_exhaust": "999950816643950720086181245", + "delivered_raw_token": "999950816643950720086181245", + "upper_residue_raw_token": "0", + "core_dust_before_exhaust": { + "raw_token": "2", + "raw_quote": "3" + }, + "core_dust_after_exhaust": { + "raw_token": "2", + "raw_quote": "3" + } + } + ] + }, + "start": { + "contract": [ + { + "block_time": 5000, + "tradingStart": "4999", + "create": "InvalidTradingStart (create and preview)", + "trade_at_block_time": null, + "trade_at_start": null + }, + { + "block_time": 5000, + "tradingStart": "5000", + "create": "ok", + "trade_at_block_time": "ok", + "trade_at_start": "ok" + }, + { + "block_time": 5000, + "tradingStart": "5001", + "create": "ok", + "trade_at_block_time": "TradingNotStarted", + "trade_at_start": "ok" + }, + { + "block_time": 5000, + "tradingStart": "91400", + "create": "ok", + "trade_at_block_time": "TradingNotStarted", + "trade_at_start": "ok" + }, + { + "block_time": 5000, + "tradingStart": "18446744073709551615", + "create": "ok (contract has no cap; effectively indefinite self-lock)", + "trade_at_block_time": "TradingNotStarted", + "trade_at_start": "not exercised (astronomically distant timestamp)" + } + ], + "contract_mined_late": { + "previewed_at": 5000, + "tradingStart": 5000, + "mined_at": 5001, + "create": "InvalidTradingStart, no token and no pool left" + }, + "producer_proposal": { + "status": "local reference proposal for CTO freeze; not a live/hosted selection", + "rule": "buildTime + minMargin <= tradingStart <= buildTime + maxDelay and buildTime < expiry <= tradingStart; never rewrite a signed start", + "minMargin_s": 300, + "maxDelay_s": 86400, + "vectors": [ + { + "buildTime": 1000, + "tradingStart": 1000, + "expiry": 1000, + "verdict": "refuse: start-now (start <= buildTime)" + }, + { + "buildTime": 1000, + "tradingStart": 1299, + "expiry": 1299, + "verdict": "refuse: start below margin" + }, + { + "buildTime": 1000, + "tradingStart": 1300, + "expiry": 1300, + "verdict": "accept: minimum start, expiry at start" + }, + { + "buildTime": 1000, + "tradingStart": 1300, + "expiry": 1301, + "verdict": "refuse: expiry after start" + }, + { + "buildTime": 1000, + "tradingStart": 1300, + "expiry": 1000, + "verdict": "refuse: expiry not after buildTime" + }, + { + "buildTime": 1000, + "tradingStart": 1300, + "expiry": 1001, + "verdict": "accept" + }, + { + "buildTime": 1000, + "tradingStart": 87400, + "expiry": 1300, + "verdict": "accept: maximum start" + }, + { + "buildTime": 1000, + "tradingStart": 87400, + "expiry": 87400, + "verdict": "accept" + }, + { + "buildTime": 1000, + "tradingStart": 87401, + "expiry": 1300, + "verdict": "refuse: start above cap" + }, + { + "buildTime": 1000, + "tradingStart": 18446744073709551615, + "expiry": 1300, + "verdict": "refuse: start above cap (contract alone would accept and self-lock)" + } + ], + "why": "Bounds the requested start to maxDelay after buildTime. Submission before expiry does not guarantee mining before start: late mining reverts atomically. No inclusion-latency guarantee." + } + }, + "claim_recipient_refusals": { + "error": "InvalidRecipient() (periphery)", + "refused": [ + "address(0)", + "Core", + "extension", + "periphery", + "poolKey.token0", + "poolKey.token1" + ], + "accepted_examples": [ + "owner", + "EOA", + "other contract (ETH-receiving for a native quote)" + ], + "atomicity": "both assets or neither; a reverting native recipient or a refused ERC-20 transfer rolls the ledger, principal and Core balances back; retry to another recipient pays both in full", + "reentrancy": "the ledger is moved onto the lock before Core pays; an owner contract re-entering claimFees during the payment claims zero" + }, + "metadata": { + "encoding": "Canonical LibString.packOne: first byte length 1..31, next length bytes content, all remaining bytes zero", + "unit": "bytes, not characters; UTF-8 is a consumer policy, not contract validation", + "error": "InvalidMetadata()", + "checked_in": [ + "create", + "previewInstallation" + ], + "decimals": 18, + "examples": { + "Zero Seed": "0x095a65726f205365656400000000000000000000000000000000000000000000", + "ZERO": "0x045a45524f000000000000000000000000000000000000000000000000000000" + }, + "refused": [ + "zero", + "length 0", + "length >31", + "nonzero tail" + ], + "note": "LibString.packOne assumes memory padding; producers must explicitly zero the tail. No truncation." + }, + "collision": { + "error": "LaunchTokenExists(address token)", + "checked_in": [ + "create", + "previewInstallation" + ], + "rule": "CREATE2(extension, keccak256(abi.encode(controller,salt)), keccak256(LaunchToken.creationCode ++ abi.encode(bytes32 name,bytes32 symbol))); logo is excluded" + }, + "fee_curve": { + "note": "Tick-rate schedule. Digests: SHA-256 chain h = sha256(h || fee as 8-byte big-endian) over the sampled seconds t = 0, step, 2*step, ..., last inclusive; all from the independent Python oracle (exact port of the tick table).", + "rates_q64": { + "5": "922337203685477580", + "50": "9223372036854775808", + "75": "13835058055282163712", + "90": "16602069666338596454", + "99": "18262276632972456099", + "99.9": "18428297329635842064", + "max": "18446744073709551615" + }, + "final_fee_q64": "55340232221128654", + "decay_rates_x32": { + "default_one_day": "68913100933", + "600s": "9923486534471", + "two_ticks_per_second": "8589934592", + "quarter_tick_per_second": "1073741824", + "tenth_tick_per_second_floor": "429496729", + "min": "1", + "max": "18446744073709551615" + }, + "half_life_s": { + "default_one_day": "86400.00000104363", + "600s": "600.00000000005238", + "two_ticks_per_second": "693151.52713347783 (8.0225408233 days)", + "quarter_tick_per_second": "5545180.2170678226 (64.18 days)", + "min": "5954091920683119 (about 1.89e8 years)", + "max": "0.0000000003229 (saturates within the first second)" + }, + "saturation_second": { + "default_one_day": "5529597", + "600s": "38399", + "two_ticks_per_second": "44361417", + "quarter_tick_per_second": "354891343", + "min": "381061679028371455", + "max": "0" + }, + "saturation_note": "saturation_second = MAX_DECAY_PRODUCT / decayRateX32 is the last elapsed second computed through the helper; from the next second the fee is exactly finalFee. On the 50% -> 0.3% fixtures the floored excess is already zero earlier (rounding), so the two mechanisms coincide at the floor; a full-span excess (2**64 - 1 -> 0) still leaves 1 raw unit when the magnitude is exactly 88,722,835 at saturation_second, which is why the guard rather than a clamp to the minimum tick yields finalFee.", + "digests_sha256": [ + { + "label": "default 50% -> 0.3%, every second 0..3600", + "initialFee": "9223372036854775808", + "finalFee": "55340232221128654", + "decayRateX32": "68913100933", + "last": 3600, + "step": 1, + "digest": "c3de4d91d476acc61f73455efe7fb8c750b89de3759a0c500bbde0bdf9bcd062" + }, + { + "label": "default 50% -> 0.3%, every minute 0..30 days", + "initialFee": "9223372036854775808", + "finalFee": "55340232221128654", + "decayRateX32": "68913100933", + "last": 2592000, + "step": 60, + "digest": "b2c022f5cbbc90cedca9834bcf64f636b97c45dee08c730ab4dbf17d8d5acc74" + }, + { + "label": "600 s half-life 5% -> 0.3%, every second 0..3600", + "initialFee": "922337203685477580", + "finalFee": "55340232221128654", + "decayRateX32": "9923486534471", + "last": 3600, + "step": 1, + "digest": "c4db35cd45f48222463cb9a940c506599715162db6c37b01428331ff5263bdc6" + }, + { + "label": "2 ticks/s 99.9% -> 0, every hour 0..30 days", + "initialFee": "18428297329635842064", + "finalFee": "0", + "decayRateX32": "8589934592", + "last": 2592000, + "step": 3600, + "digest": "8fdefff5fe4cfb98c43bbbf6ed6f0b9a0ae398f1f810ffea0522d5504e1321da" + }, + { + "label": "1/4 tick/s max -> 0, every second 0..3600", + "initialFee": "18446744073709551615", + "finalFee": "0", + "decayRateX32": "1073741824", + "last": 3600, + "step": 1, + "digest": "11ff0a905ab22707579e714aba31b895ed3234788a0dab10b0daa0881a9ccf36" + } + ], + "tables": { + "default_one_day_50_to_0.3": [ + { + "t": "0", + "fee_q64": "9223372036854775808", + "pct": "50.0000000000" + }, + { + "t": "1", + "fee_q64": "9223298692930386783", + "pct": "49.9996024018", + "tick_magnitude": "16" + }, + { + "t": "60", + "fee_q64": "9218963276153076996", + "pct": "49.9761000603", + "tick_magnitude": "962" + }, + { + "t": "3600", + "fee_q64": "8962377276946957658", + "pct": "48.5851445715", + "tick_magnitude": "57762" + }, + { + "t": "43200", + "fee_q64": "6538119400055406284", + "pct": "35.4432162875", + "tick_magnitude": "693147" + }, + { + "t": "86400", + "fee_q64": "4639356258918185573", + "pct": "25.1500006743", + "tick_magnitude": "1386295" + }, + { + "t": "172800", + "fee_q64": "2347348307759775472", + "pct": "12.7250006743", + "tick_magnitude": "2772590" + }, + { + "t": "604800", + "fee_q64": "126965494298918151", + "pct": "0.6882813237", + "tick_magnitude": "9704065" + }, + { + "t": "2592000", + "fee_q64": "55340240759526319", + "pct": "0.3000000463", + "tick_magnitude": "41588851" + }, + { + "t": "5529597", + "fee_q64": "55340232221128654", + "pct": "0.3000000000", + "tick_magnitude": "88722835" + }, + { + "t": "5529598", + "fee_q64": "55340232221128654", + "pct": "0.3000000000" + } + ], + "two_ticks_per_second_50_to_0.3": [ + { + "t": "0", + "fee_q64": "9223372036854775808", + "pct": "50.0000000000" + }, + { + "t": "1", + "fee_q64": "9223362868832139196", + "pct": "49.9999503000", + "tick_magnitude": "2" + }, + { + "t": "60", + "fee_q64": "9222821971723649262", + "pct": "49.9970180909", + "tick_magnitude": "120" + }, + { + "t": "3600", + "fee_q64": "9190426476420833039", + "pct": "49.8214017590", + "tick_magnitude": "7200" + }, + { + "t": "43200", + "fee_q64": "8835746255246636721", + "pct": "47.8986764273", + "tick_magnitude": "86400" + }, + { + "t": "86400", + "fee_q64": "8464509350746382498", + "pct": "45.8861971355", + "tick_magnitude": "172800" + }, + { + "t": "172800", + "fee_q64": "7768459773126180960", + "pct": "42.1129048144", + "tick_magnitude": "345600" + }, + { + "t": "604800", + "fee_q64": "5062770843274302024", + "pct": "27.4453357354", + "tick_magnitude": "1209600" + }, + { + "t": "2592000", + "fee_q64": "741753037726786584", + "pct": "4.0210512748", + "tick_magnitude": "5184000" + }, + { + "t": "44361417", + "fee_q64": "55340232221128654", + "pct": "0.3000000000", + "tick_magnitude": "88722834" + }, + { + "t": "44361418", + "fee_q64": "55340232221128654", + "pct": "0.3000000000" + } + ], + "two_ticks_per_second_99.9_to_0": [ + { + "t": "0", + "fee_q64": "18428297329635842064", + "pct": "99.9000000000" + }, + { + "t": "1", + "fee_q64": "18428278901356940707", + "pct": "99.8999001001", + "tick_magnitude": "2" + }, + { + "t": "60", + "fee_q64": "18427191665519151079", + "pct": "99.8940061828", + "tick_magnitude": "120" + }, + { + "t": "3600", + "fee_q64": "18362074764497997343", + "pct": "99.5410067550", + "tick_magnitude": "7200" + }, + { + "t": "43200", + "fee_q64": "17649146110668978989", + "pct": "95.6762127785", + "tick_magnitude": "86400" + }, + { + "t": "86400", + "fee_q64": "16902937523957200381", + "pct": "91.6310079243", + "tick_magnitude": "172800" + }, + { + "t": "172800", + "fee_q64": "15503835857875547793", + "pct": "84.0464625948", + "tick_magnitude": "345600" + }, + { + "t": "604800", + "fee_q64": "10065237787609899792", + "pct": "54.5637633795", + "tick_magnitude": "1209600" + }, + { + "t": "2592000", + "fee_q64": "1379731172434914028", + "pct": "7.4795376730", + "tick_magnitude": "5184000" + } + ], + "default_one_day_max_to_0": [ + { + "t": "0", + "fee_q64": "18446744073709551615", + "pct": "100.0000000000" + }, + { + "t": "1", + "fee_q64": "18446596500421042511", + "pct": "99.9992000036", + "tick_magnitude": "16" + }, + { + "t": "60", + "fee_q64": "18437873327830881974", + "pct": "99.9519115902", + "tick_magnitude": "962" + }, + { + "t": "3600", + "fee_q64": "17921603711721989946", + "pct": "97.1532083934", + "tick_magnitude": "57762" + }, + { + "t": "43200", + "fee_q64": "13043821263248043520", + "pct": "70.7106967556", + "tick_magnitude": "693147" + }, + { + "t": "86400", + "fee_q64": "9223372287116814725", + "pct": "50.0000013567", + "tick_magnitude": "1386295" + }, + { + "t": "172800", + "fee_q64": "4611686268689430216", + "pct": "25.0000013567", + "tick_magnitude": "2772590" + }, + { + "t": "604800", + "fee_q64": "144115215448268606", + "pct": "0.7812501484", + "tick_magnitude": "9704065" + }, + { + "t": "2592000", + "fee_q64": "17179874578", + "pct": "9.31E-8", + "tick_magnitude": "41588851" + }, + { + "t": "5529597", + "fee_q64": "1", + "pct": "0E-10", + "tick_magnitude": "88722835" + }, + { + "t": "5529598", + "fee_q64": "0", + "pct": "0E-10" + } + ], + "min_rate_max_to_0": [ + { + "t": "0", + "fee_q64": "18446744073709551615", + "pct": "100.0000000000" + }, + { + "t": "4294967295", + "fee_q64": "18446744073709551615", + "pct": "100.0000000000", + "tick_magnitude": "0" + }, + { + "t": "4294967296", + "fee_q64": "18446734850344432283", + "pct": "99.9999500000", + "tick_magnitude": "1" + }, + { + "t": "381061679028371454", + "fee_q64": "1", + "pct": "0E-10", + "tick_magnitude": "88722835" + }, + { + "t": "381061679028371455", + "fee_q64": "1", + "pct": "0E-10", + "tick_magnitude": "88722835" + }, + { + "t": "381061679028371456", + "fee_q64": "0", + "pct": "0E-10" + }, + { + "t": "18446744073709551615", + "fee_q64": "0", + "pct": "0E-10" + } + ] + }, + "tick_steps": [ + { + "decayRateX32": "1073741824", + "note": "1/4 tick/s: the fee steps every 4 s", + "rows": [ + { + "t": "1", + "fee_q64": "9223372036854775808", + "pct": "50.0000000000", + "tick_magnitude": "0" + }, + { + "t": "3", + "fee_q64": "9223372036854775808", + "pct": "50.0000000000", + "tick_magnitude": "0" + }, + { + "t": "4", + "fee_q64": "9223367452842311500", + "pct": "49.9999751500", + "tick_magnitude": "1" + }, + { + "t": "5", + "fee_q64": "9223367452842311500", + "pct": "49.9999751500", + "tick_magnitude": "1" + }, + { + "t": "7", + "fee_q64": "9223367452842311500", + "pct": "49.9999751500", + "tick_magnitude": "1" + }, + { + "t": "8", + "fee_q64": "9223362868832139196", + "pct": "49.9999503000", + "tick_magnitude": "2" + }, + { + "t": "9", + "fee_q64": "9223362868832139196", + "pct": "49.9999503000", + "tick_magnitude": "2" + } + ] + }, + { + "decayRateX32": "429496729", + "note": "floor(0.1 * 2**32), slightly below one tick per 10 s: first step at 11 s", + "rows": [ + { + "t": "9", + "fee_q64": "9223372036854775808", + "pct": "50.0000000000", + "tick_magnitude": "0" + }, + { + "t": "10", + "fee_q64": "9223372036854775808", + "pct": "50.0000000000", + "tick_magnitude": "0" + }, + { + "t": "11", + "fee_q64": "9223367452842311500", + "pct": "49.9999751500", + "tick_magnitude": "1" + }, + { + "t": "20", + "fee_q64": "9223367452842311500", + "pct": "49.9999751500", + "tick_magnitude": "1" + }, + { + "t": "21", + "fee_q64": "9223362868832139196", + "pct": "49.9999503000", + "tick_magnitude": "2" + }, + { + "t": "30", + "fee_q64": "9223362868832139196", + "pct": "49.9999503000", + "tick_magnitude": "2" + }, + { + "t": "31", + "fee_q64": "9223358284824258897", + "pct": "49.9999254501", + "tick_magnitude": "3" + } + ] + }, + { + "decayRateX32": "68913100933", + "note": "default: 16 whole ticks per second, 1,386,295 after one day", + "rows": [ + { + "t": "1", + "fee_q64": "9223298692930386783", + "pct": "49.9996024018", + "tick_magnitude": "16" + }, + { + "t": "2", + "fee_q64": "9223225349592746513", + "pct": "49.9992048068", + "tick_magnitude": "32" + }, + { + "t": "86400", + "fee_q64": "4639356258918185573", + "pct": "25.1500006743", + "tick_magnitude": "1386295" + } + ] + }, + { + "decayRateX32": "68913100933", + "note": "a one-unit excess is gone after the first whole tick", + "rows": [ + { + "t": "0", + "fee_q64": "55340232221128655", + "pct": "0.3000000000" + }, + { + "t": "1", + "fee_q64": "55340232221128654", + "pct": "0.3000000000", + "tick_magnitude": "16" + } + ] + } + ], + "oracle_error_bounds": { + "note": "Integer result minus the real-number F + (I - F) * 1.000001**(-(decayRateX32 / 2**32) * t / 2) at 150 digits, default 50% -> 0.3%, every second of the first hour then every 10 minutes to 30 days. The error is dominated by the whole-tick floor of m (one tick = 5e-7 of the excess), not by the helper (which is within a few units of 2**-128 of the real sqrt ratio) or the final floor.", + "max_abs_q64": "4574692217333.041", + "at_t": "244", + "max_abs_fraction_of_excess": "4.98983E-7", + "one_tick_of_excess_fraction": "5.00000E-7" + } + }, + "creator_fee_range": { + "type": "uint64, Q0.64 (2**64 = 100%)", + "min_q64": "0", + "max_q64": "18446744073709551615", + "max_fraction": "1 - 2**-64: just under 100%, not 100%", + "constant": "MAX_CREATOR_FEE = type(uint64).max (src/extensions/ZeroSeedLaunch.sol); no ceiling comparison in _validate", + "schedule_rules": [ + "finalFee <= initialFee" + ], + "error": "InvalidFeeSchedule() 0xf75a271a", + "checked_in": [ + "create", + "previewInstallation", + "forwarded create payload" + ], + "unencodable": { + "value": "18446744073709551616", + "meaning": "exactly 100% = 2**64", + "verdict": "ABI decoding failure in create(parameters,logoUrl), previewInstallation and forwarded create for either fee word; no truncation", + "dirty_high_bits": { + "value": "36893488147419103231", + "note": "2**64 + (2**64 - 1)", + "verdict": "same ABI decoding failure" + } + }, + "vectors": [ + { + "initialFee": "18446744073709551615", + "finalFee": "55340232221128654", + "decayRateX32": "68913100933", + "verdict": "accept", + "note": "max -> 0.3% at the default one-day half-life" + }, + { + "initialFee": "18446744073709551615", + "finalFee": "18446744073709551615", + "decayRateX32": "1", + "verdict": "accept", + "note": "flat at the maximum, slowest rate" + }, + { + "initialFee": "18446744073709551615", + "finalFee": "18446744073709551615", + "decayRateX32": "18446744073709551615", + "verdict": "accept", + "note": "flat at the maximum, fastest rate" + }, + { + "initialFee": "18446744073709551615", + "finalFee": "0", + "decayRateX32": "18446744073709551615", + "verdict": "accept", + "note": "max -> 0 at the fastest rate: saturated to 0 from t = 1" + }, + { + "initialFee": "18446744073709551615", + "finalFee": "0", + "decayRateX32": "1", + "verdict": "accept", + "note": "max -> 0 at the slowest rate: one raw unit at t = MAX_DECAY_PRODUCT (minimum tick residual), 0 from t = MAX_DECAY_PRODUCT + 1" + }, + { + "initialFee": "0", + "finalFee": "0", + "decayRateX32": "68913100933", + "verdict": "accept", + "note": "zero schedule" + }, + { + "initialFee": "922337203685477580", + "finalFee": "55340232221128654", + "decayRateX32": "0", + "verdict": "accept", + "note": "zero rate: flat at initialFee forever" + }, + { + "initialFee": "18446744073709551614", + "finalFee": "18446744073709551615", + "decayRateX32": "68913100933", + "verdict": "InvalidFeeSchedule", + "note": "final above initial at the top of the range" + }, + { + "initialFee": "0", + "finalFee": "1", + "decayRateX32": "68913100933", + "verdict": "InvalidFeeSchedule" + }, + { + "initialFee": "922337203685477580", + "finalFee": "922337203685477581", + "decayRateX32": "0", + "verdict": "InvalidFeeSchedule", + "note": "shape is checked even at a zero rate" + }, + { + "initialFee": "18446744073709551616", + "finalFee": "18446744073709551615", + "decayRateX32": "68913100933", + "verdict": "abi_decoding_failure", + "note": "2**64 in initialFee" + }, + { + "initialFee": "18446744073709551615", + "finalFee": "18446744073709551616", + "decayRateX32": "68913100933", + "verdict": "abi_decoding_failure", + "note": "2**64 in finalFee" + }, + { + "initialFee": "18446744073709551615", + "finalFee": "55340232221128654", + "decayRateX32": "18446744073709551616", + "verdict": "abi_decoding_failure", + "note": "2**64 in decayRateX32" + } + ], + "reference_schedules": { + "fixture": { + "initialFee": "922337203685477580", + "finalFee": "55340232221128654", + "decayRateX32": "68913100933", + "note": "5% -> 0.3% at the default one-day half-life: this fixture's local reference parameters" + }, + "consumer_default": { + "initialFee": "9223372036854775808", + "finalFee": "55340232221128654", + "decayRateX32": "68913100933", + "half_life_s": "86400.0000010436", + "fee_after_one_day_q64": "4639356258918185573", + "fee_after_one_day_pct": "25.1500006743", + "note": "50% -> 0.3% with a one-day half-life of the excess: the consumer-side default; a creation parameter choice, not a contract constant. About 25.15% after one day, 12.73% after two, 0.69% after seven; the floor is approached, not scheduled." + } + }, + "decay_rate_rules": [ + "any uint64 decayRateX32 is accepted, including 0 (flat at initialFee) and 2**64 - 1 (finalFee from the first second)" + ] + }, + "max_rate": { + "note": "Launches created through ZeroSeedLaunchPeriphery.create at initialFee = 2**64 - 1 (no storage injection), finalFee = 0.3%, default one-day half-life rate 68913100933, traded at tradingStart. Exact input: net = floor(gross / 2**64), fee = gross - net = ceil(gross * (2**64 - 1) / 2**64). Exact output: paid = calc * 2**64, fee = paid - calc. Settled by the local test lockers against locally compiled Core; not live evidence.", + "first_buy_note": "The first whole-quote-unit buy is identical for the max -> 0.3% / default rate, max -> max / rate 1 and max -> 0 / rate 2**64 - 1 schedules (the rate at tradingStart is the initial rate in every case).", + "trades": [ + { + "rate": "max", + "order": "t0", + "dec": "18/18", + "gross": "982941", + "fee": "982941", + "net": "0", + "decimals": "18/18", + "step": "oneUnit" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/18", + "quoteIn": "1000000000000000000", + "gross": "982091443427432213915088", + "fee": "982091443427432213861849", + "net": "53239", + "decimals": "18/18", + "step": "buyExactIn" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/18", + "tokenOut": "53239", + "calcQuote": "1", + "fee": "18446744073709551615", + "paid": "18446744073709551616", + "decimals": "18/18", + "step": "buyExactOut" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/18", + "tokenIn": "106478", + "grossQuote": "0", + "fee": "0", + "quoteOut": "0", + "roundTripLoss": "19446744073709551617", + "decimals": "18/18", + "step": "sellAll" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/6", + "gross": "984538387033333867", + "fee": "984538387033333867", + "net": "0", + "decimals": "18/6", + "step": "oneUnit" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/6", + "quoteIn": "1000000", + "gross": "983667635470798139337767", + "fee": "983667635470798139284443", + "net": "53324", + "decimals": "18/6", + "step": "buyExactIn" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/6", + "tokenOut": "53324", + "calcQuote": "1", + "fee": "18446744073709551615", + "paid": "18446744073709551616", + "decimals": "18/6", + "step": "buyExactOut" + }, + { + "rate": "max", + "order": "t0", + "dec": "18/6", + "tokenIn": "106648", + "grossQuote": "0", + "fee": "0", + "quoteOut": "0", + "roundTripLoss": "18446744073710551617", + "decimals": "18/6", + "step": "sellAll" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/18", + "gross": "729761", + "fee": "729761", + "net": "0", + "decimals": "18/18", + "step": "oneUnit" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/18", + "quoteIn": "1000000000000000000", + "gross": "982091443427432212980275", + "fee": "982091443427432212927036", + "net": "53239", + "decimals": "18/18", + "step": "buyExactIn" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/18", + "tokenOut": "53239", + "calcQuote": "1", + "fee": "18446744073709551615", + "paid": "18446744073709551616", + "decimals": "18/18", + "step": "buyExactOut" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/18", + "tokenIn": "106478", + "grossQuote": "0", + "fee": "0", + "quoteOut": "0", + "roundTripLoss": "19446744073709551617", + "decimals": "18/18", + "step": "sellAll" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/6", + "gross": "467398106332855075", + "fee": "467398106332855075", + "net": "0", + "decimals": "18/6", + "step": "oneUnit" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/6", + "quoteIn": "1000000", + "gross": "983666653587480924554914", + "fee": "983666653587480924501590", + "net": "53324", + "decimals": "18/6", + "step": "buyExactIn" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/6", + "tokenOut": "53324", + "calcQuote": "1", + "fee": "18446744073709551615", + "paid": "18446744073709551616", + "decimals": "18/6", + "step": "buyExactOut" + }, + { + "rate": "max", + "order": "t1", + "dec": "18/6", + "tokenIn": "106648", + "grossQuote": "0", + "fee": "0", + "quoteOut": "0", + "roundTripLoss": "18446744073710551617", + "decimals": "18/6", + "step": "sellAll" + } + ], + "trades_note": "Actual maximum-rate fills on the final geometry; oneUnit buys net zero, exact output grosses up the input; see trade rows for exact amounts", + "exact_output_bounds": { + "note": "Bisection over the requested launch-token output on the pinned fixture: the last request that executes, the first that fails the signed int128 conversion of the fee-inclusive input (calc * 2**64 >= 2**127), and the first that fails the uint128 gross-up helper (calc >= 2**64). The last executable request has calc = 2**63 - 1 exactly. Every failed probe rolls back pool state, fee ledger, position liquidity and Core balances.", + "signed_bound_calc": "9223372036854775807", + "helper_bound_calc": "18446744073709551615", + "errors": { + "signed": "SafeCastLib.Overflow() 0x35278d12", + "helper": "AmountBeforeFeeOverflow() 0x0d88f526" + }, + "vectors": [ + { + "rate": "max", + "order": "t0", + "lastValidTokenOut": "8992894608587101713726987", + "calc": "9223372036854775807", + "paid": "170141183460469231713240559642174554112", + "firstSignedOverflowTokenOut": "8992894608587101713726988", + "lastSignedOverflowTokenOut": "17841529728048229186238638", + "firstHelperOverflowTokenOut": "17841529728048229186238639", + "decimals": "18/18" + }, + { + "rate": "max", + "order": "t1", + "lastValidTokenOut": "8992894608587101713646726", + "calc": "9223372036854775807", + "paid": "170141183460469231713240559642174554112", + "firstSignedOverflowTokenOut": "8992894608587101713646727", + "lastSignedOverflowTokenOut": "17841529728048229186058949", + "firstHelperOverflowTokenOut": "17841529728048229186058950", + "decimals": "18/18" + } + ] + } + }, + "forward_schema": { + "swap": { + "payload": "abi.encode(PoolKey, SwapParameters)", + "length": 128, + "returns": "abi.encode(PoolBalanceUpdate, PoolState)", + "first_word": "PoolKey.token0 < 2**160" + }, + "create": { + "tag": "0x224a5a98239f599168b798c4205db155bfff4332b4931a7fb5bc60c2e2eeee30", + "tag_source": "keccak256(\"IZeroSeedLaunch#CREATE\")", + "payload": "abi.encode(ZERO_SEED_LAUNCH_CREATE, LaunchParameters, string logoUrl)", + "returns": "abi.encode(Installation)", + "controller": "Locker.addr() of the forwarding locker", + "lock_debt_after": "zero" + }, + "claim_fees": { + "tag": "0xe52d8a05fd0f2d32b280675736d8117fee83069a0eac7ab9279aa52ff05a614c", + "tag_source": "keccak256(\"IZeroSeedLaunch#CLAIM_FEES\")", + "payload": "abi.encode(tag, PoolKey)", + "returns": "abi.encode(uint128 amount0, uint128 amount1)", + "authorization": "launch.controller == Locker.addr()", + "lock_debt_after": "credit of (amount0, amount1) for the locker to withdraw" + }, + "unknown": "any first word >= 2**160 that is not a tag, or fewer than 32 bytes, reverts UnknownForwardAction(); a first word < 2**160 is decoded as a swap" + }, + "abi": { + "ZeroSeedLaunch": { + "selectors": { + "afterCollectFees(bytes32,(address,address,bytes32),bytes32,uint128,uint128)": "0x751fd5df", + "afterInitializePool(address,(address,address,bytes32),int32,uint96)": "0x948374ff", + "afterSwap(bytes32,(address,address,bytes32),bytes32,bytes32,bytes32)": "0xa4e8f288", + "afterUpdatePosition(bytes32,(address,address,bytes32),bytes32,int128,bytes32,bytes32)": "0x25fa4e69", + "beforeCollectFees(bytes32,(address,address,bytes32),bytes32)": "0xdf65d8d1", + "beforeInitializePool(address,(address,address,bytes32),int32)": "0x1fbbb462", + "beforeSwap(bytes32,(address,address,bytes32),bytes32)": "0xca11dba7", + "beforeUpdatePosition(bytes32,(address,address,bytes32),bytes32,int128)": "0x0035c723", + "creatorFees((address,address,bytes32))": "0xb4ce9a2e", + "feeAt(bytes32,uint256)": "0xe81084ec", + "forwarded_2374103877(bytes32)": "0x00000001", + "getLaunch(bytes32)": "0x7d1d589c", + "previewInstallation(address,(bytes32,bytes32,uint128,address,int32,int32,uint64,uint64,uint64,uint64,bytes32))": "0xd215dcb2" + }, + "errors": { + "BaseForwardeeAccountantOnly()": "0x588e1740", + "BoundsOrder()": "0x68651c5c", + "BoundsTickSpacing()": "0x89fd41b1", + "CallPointNotImplemented()": "0xc6f26286", + "ControllerOnly()": "0xac8ff76a", + "CoreOnly()": "0x62279cff", + "InitializeThroughCreateOnly()": "0x028eb443", + "InvalidFeeSchedule()": "0xf75a271a", + "InvalidMetadata()": "0xbcecb64a", + "InvalidSupply()": "0x15ae6727", + "InvalidTick(int32)": "0x073ee172", + "InvalidTicks()": "0x1434ed7f", + "InvalidTradingStart()": "0xe0839259", + "LaunchTokenExists(address)": "0xf68475cd", + "LiquidityAboveTickCap(uint128,uint128)": "0x20ea795f", + "MinMaxBounds()": "0xabfa4a31", + "PositionsThroughCreateOnly()": "0x74a99003", + "StableswapMustBeFullRange()": "0x72b1019d", + "SwapsThroughForwardOnly()": "0xf17f54b3", + "TradingNotStarted()": "0xacf75be8", + "UnknownForwardAction()": "0xe5c78d9a", + "UnknownLaunch()": "0xf6806bf8", + "UnsupportedQuoteToken()": "0x658d8331", + "ZeroLiquidity()": "0x10074548" + }, + "events": { + "CreatorFeesClaimed(bytes32,address,uint128,uint128)": "0xf0ffdfa84530baef2e9f8bbb160545a59bfef8da319fa27aa69e4f3c8f05a41d", + "LaunchCreated(bytes32,address,address,(address,address,bytes32),bytes32,uint128,(bytes32,bytes32,uint128,address,int32,int32,uint64,uint64,uint64,uint64,bytes32),string)": "0x0a54c7540832cb23832d30bbf27c5597cfb779d070a1c253a7aee90571c2da4c", + "LaunchSwapped(bytes32,address,int128,int128,uint64,uint128,bool)": "0x3e58795f52a8e88efdec2da89ea3798175f8764145ccd7bf5e40633a7d571f6d" + } + }, + "ZeroSeedLaunchPeriphery": { + "selectors": { + "LAUNCH()": "0x096e3c3e", + "claimFees((address,address,bytes32),address)": "0x6906b4c0", + "create((bytes32,bytes32,uint128,address,int32,int32,uint64,uint64,uint64,uint64,bytes32),string)": "0x9a09bd5d", + "launchOwner(bytes32)": "0x60ac0b66", + "locked_6416899205(uint256)": "0x00000000", + "previewInstallation(address,(bytes32,bytes32,uint128,address,int32,int32,uint64,uint64,uint64,uint64,bytes32))": "0xd215dcb2", + "transferLaunch(bytes32,address)": "0x8b1cb36f" + }, + "errors": { + "BaseLockerAccountantOnly()": "0x3ed2a9c0", + "ExpectedRevertWithinLock()": "0x4c816e2b", + "InvalidOwner()": "0x49e27cff", + "InvalidRecipient()": "0x9c8d2cd2", + "OwnerOnly()": "0x596dcdb8" + }, + "events": { + "LaunchFeesClaimed(bytes32,address,address,uint128,uint128)": "0x908c6b2c19765fe47aef218b4f71ea1a10a9e156d9d5c3500c3a298e01428805", + "LaunchOwnerChanged(bytes32,address,address)": "0x478004cf03e8c3b648608ce0259ce479c813aa671a383230ee7763fe5da22391" + } + }, + "LaunchToken": { + "selectors": { + "DOMAIN_SEPARATOR()": "0x3644e515", + "allowance(address,address)": "0xdd62ed3e", + "approve(address,uint256)": "0x095ea7b3", + "balanceOf(address)": "0x70a08231", + "decimals()": "0x313ce567", + "mint(address,uint128,uint128)": "0x97622870", + "name()": "0x06fdde03", + "nonces(address)": "0x7ecebe00", + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)": "0xd505accf", + "symbol()": "0x95d89b41", + "totalSupply()": "0x18160ddd", + "transfer(address,uint256)": "0xa9059cbb", + "transferFrom(address,address,uint256)": "0x23b872dd" + }, + "errors": { + "AllowanceOverflow()": "0xf9067066", + "AllowanceUnderflow()": "0x8301ab38", + "InsufficientAllowance()": "0x13be252b", + "InsufficientBalance()": "0xf4d678b8", + "InvalidPermit()": "0xddafbaef", + "MintClosed()": "0x589ed34b", + "Permit2AllowanceIsFixedAtInfinity()": "0x3f68539a", + "PermitExpired()": "0x1a15a3cc", + "TotalSupplyOverflow()": "0xe5cfe957" + }, + "events": { + "Approval(address,address,uint256)": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "Transfer(address,address,uint256)": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + } + }, + "pins": { + "runtime_templates": { + "ZeroSeedLaunch": { + "bytes": 18366, + "keccak256": "0x707be0d4e2c25c21d6d9aafec5bb58e634118c1edade48d0dc1fd5be5de2624c" + }, + "ZeroSeedLaunchPeriphery": { + "bytes": 6123, + "keccak256": "0xe6c0d086bff1c96e4f0a2e8068022795a0c74f96d15d15cd041cbea2d2e9b529" + }, + "LaunchToken": { + "bytes": 3012, + "keccak256": "0xec01758e39962fca797fc966e3e541ac87c2c72814b9e1ab86d6193597b182b6" + } + }, + "creationCode": { + "ZeroSeedLaunch": { + "bytes": 18884, + "keccak256": "0x6ec3a947c32774eab196724fd1a98c4eb927af430dec7ed1b111be414d85dc20" + }, + "ZeroSeedLaunchPeriphery": { + "bytes": 6343, + "keccak256": "0x4698c93153732a8f4371252ca5af048a7fe5a181dbd6e26ee4e76f2c942abaf2" + }, + "LaunchToken": { + "bytes": 3172, + "keccak256": "0xb92240f5b935a76e949aab04e7e9e4a0a28adc3ff1a89a349c67dcaab13ea432" + } + } + }, + "supply": { + "min": "1", + "max": "1000000000000000000000000000000", + "type": "uint128", + "error": "InvalidSupply()" + }, + "spacing": { + "rule": "s = ceil((upperTick-askTick)/256); ask = ceil(askTick/s)*s; upper = floor(upperTick/s)*s", + "max": 693148, + "skipAhead": 1, + "reference": "zero-seed-launch-installation.json" + }, + "logo": { + "location": "second argument of create and final field of LaunchCreated", + "default": "", + "stored": false, + "in_preview_or_token_or_pool_identity": false + } +}