@ostraagent/mcp 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/ostra-mcp.js +459 -223
- package/package.json +1 -1
package/dist/ostra-mcp.js
CHANGED
|
@@ -18,7 +18,7 @@ var __export = (target, all) => {
|
|
|
18
18
|
var define_OSTRA_PACKAGED_default;
|
|
19
19
|
var init_define_OSTRA_PACKAGED = __esm({
|
|
20
20
|
"<define:OSTRA_PACKAGED>"() {
|
|
21
|
-
define_OSTRA_PACKAGED_default = { version: "0.1.
|
|
21
|
+
define_OSTRA_PACKAGED_default = { version: "0.1.5", deployment: { version: 1, chainId: 4663, fromBlock: "91991509", token: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", batchSettlement: "0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003", vaultImplementation: "0xD20c6744Cfa46d9ec564b119cC923bAb2f9f9331", vaultBeacon: "0xE9F525B9EaeE48d13AEd28fE146F48f2832a18a0", vaultFactory: "0x043a15c514CFE2c797d33520bFF91a5DCdbf2979", poolImplementation: "0xC04d4a222dC1C966640B977608bE29949b0648ec", poolBeacon: "0x30669Ca534921038a531BBE27116d85bB7406fFF", pool: "0x6ea80F2462e5Fd783B0Ec3B2c7BaC96795980CD6", splitFactory: "0xAAf54A483B2c7c2c5ecFc1eDED5ed1619C1bA882", beaconOwner: "0x55533a51d9bd9b06F2D179d919BB31995EF96E5e", launchpad: { hook: "0x63A784afb8905452aDceC471a45E555F5caE68cC", fees: "0x8e79671DC9729476614C78aFcf2345D4c1963801", launchpad: "0xfC57162C0e3f9773F97fEa8d276e957d7c43A6C5", creatorSplit: "0x987994dE6A1d5303B9e3F50977cB0321BA4D033B", dispatcher: "0x44Bb65164b2855f8E80B142d5Fb9bDb72E869986", locker: "0xb593812363bAd70Ee381c7B54c4FC82b0BA3A4A7", devBuy: "0x0e1Fd799E136dcfEcad5695B07Ac5DAc5B2fF4bc", vesting: "0xadD9C1995910457312c156E7D8120D1b447E179a", airdrop: "0xBC798D956aF4c2B104FFC6106d5322294Bc103bb", owner: "0x6569E27A95a6A3E92A311B4Cc6600fed56aA50A2" }, registry: "0xcE6Cc1f93744f4090DA1444Bb8590d9206157506" }, swapDeployment: { chainId: 4663, fromBlock: "94940585", router: "0x5b9686f384A5Fb768B2360cF0B893F0d1E960B01", stake: "0xaDA4FaB9c8aB9165bf4d6cD9d4Da6d6b32Bb4BC6", buyback: "0xd86083031b7Af66ecD5C9c5e90D4C6d8E661F3f5", spendVerifier: "0x0a0E28a81DE6289e5044950163FfE95b37180e3B", privatePool: "0xe4250895Da2499602Cee4e178Fb46A0cF39F5b76" }, prover: { wasm: "0xd5f3069334ab49a2f955e4b4be9493b80c3f7b2a85f4ff2073a327ef5fbc2747", glue: "0x4bc8bef7c755c83daaf833623f85473a20a7c40b390d8d639d9e4353618a0537" }, relayerUrl: "https://relayer.ostraagent.xyz", keeperUrl: "https://keeper.ostraagent.xyz", aggregatorUrl: "https://aggregator.ostraagent.xyz", aiUrl: "https://ai.ostraagent.xyz" };
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -11721,7 +11721,7 @@ var init_hash = __esm({
|
|
|
11721
11721
|
});
|
|
11722
11722
|
|
|
11723
11723
|
// ../sdk/src/constants.ts
|
|
11724
|
-
var ROBINHOOD_CHAIN_ID, ROBINHOOD_PUBLIC_RPC, USDG, USDG_EIP712_DOMAIN, X402_BATCH_SETTLEMENT, X402_BATCH_SETTLEMENT_DOMAIN, X402_MIN_WITHDRAW_DELAY, X402_MAX_WITHDRAW_DELAY, UNISWAP_V4_POOL_MANAGER, CHAINLINK_ETH_USD, CHAINLINK_ETH_USD_DECIMALS, ERC8004_IDENTITY_REGISTRY, WETH, OSTRA, OSTRA_DECIMALS, OSTRA_PONS_CURVE, MULTICALL3, ARBITRUM_NODE_INTERFACE, MAX_FEE_BPS, DEPOSIT_TIMEOUT_SECONDS, VAULT_SWAP_GAS_RESERVE, VAULT_VERSION, VAULT_MAX_URI_LENGTH, VAULT_ACTION, MIN_RECOVERY_DELAY, MAX_RECOVERY_DELAY, POOL_SETTING, CIRCUIT_BREAKER, VAULT_SWAP_GAS, LAUNCHPAD, DEV_BUY, AIRDROP, CREATOR_SPLIT, DEPOSIT_STATUS, BATCH_STATUS;
|
|
11724
|
+
var ROBINHOOD_CHAIN_ID, ROBINHOOD_PUBLIC_RPC, USDG, USDG_EIP712_DOMAIN, X402_BATCH_SETTLEMENT, X402_BATCH_SETTLEMENT_DOMAIN, X402_MIN_WITHDRAW_DELAY, X402_MAX_WITHDRAW_DELAY, UNISWAP_V4_POOL_MANAGER, CHAINLINK_ETH_USD, CHAINLINK_ETH_USD_DECIMALS, ERC8004_IDENTITY_REGISTRY, WETH, OSTRA, OSTRA_DECIMALS, OSTRA_PONS_CURVE, PONS_HOOK, OSTRA_POOL_FEE, OSTRA_POOL_TICK_SPACING, MULTICALL3, ARBITRUM_NODE_INTERFACE, MAX_FEE_BPS, DEPOSIT_TIMEOUT_SECONDS, VAULT_SWAP_GAS_RESERVE, VAULT_VERSION, VAULT_MAX_URI_LENGTH, VAULT_ACTION, MIN_RECOVERY_DELAY, MAX_RECOVERY_DELAY, POOL_SETTING, CIRCUIT_BREAKER, VAULT_SWAP_GAS, LAUNCHPAD, DEV_BUY, AIRDROP, CREATOR_SPLIT, DEPOSIT_STATUS, BATCH_STATUS;
|
|
11725
11725
|
var init_constants = __esm({
|
|
11726
11726
|
"../sdk/src/constants.ts"() {
|
|
11727
11727
|
"use strict";
|
|
@@ -11747,6 +11747,9 @@ var init_constants = __esm({
|
|
|
11747
11747
|
OSTRA = "0x68Ff81dFFF6eccefb74706fE1e0a86320CB2Eb96";
|
|
11748
11748
|
OSTRA_DECIMALS = 18;
|
|
11749
11749
|
OSTRA_PONS_CURVE = "0xef89C3a9832Ae6f8Dc5F785484b1B5cb1120F372";
|
|
11750
|
+
PONS_HOOK = "0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044";
|
|
11751
|
+
OSTRA_POOL_FEE = 0;
|
|
11752
|
+
OSTRA_POOL_TICK_SPACING = 200;
|
|
11750
11753
|
MULTICALL3 = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
11751
11754
|
ARBITRUM_NODE_INTERFACE = "0x00000000000000000000000000000000000000C8";
|
|
11752
11755
|
MAX_FEE_BPS = 500;
|
|
@@ -12123,7 +12126,7 @@ var init_deployment = __esm({
|
|
|
12123
12126
|
|
|
12124
12127
|
// ../sdk/src/external-abi.ts
|
|
12125
12128
|
import { parseAbi } from "viem";
|
|
12126
|
-
var usdgAbi, chainlinkAggregatorAbi, ponsCurveAbi, multicall3Abi, nodeInterfaceAbi;
|
|
12129
|
+
var usdgAbi, chainlinkAggregatorAbi, ponsCurveAbi, poolManagerExtsloadAbi, multicall3Abi, nodeInterfaceAbi;
|
|
12127
12130
|
var init_external_abi = __esm({
|
|
12128
12131
|
"../sdk/src/external-abi.ts"() {
|
|
12129
12132
|
"use strict";
|
|
@@ -12157,6 +12160,7 @@ var init_external_abi = __esm({
|
|
|
12157
12160
|
"function getReserves() view returns (uint256 ethReserve, uint256 tokenReserve)",
|
|
12158
12161
|
"function buy(uint256 ethIn, uint256 minTokensOut, address recipient) payable returns (uint256 tokensOut)"
|
|
12159
12162
|
]);
|
|
12163
|
+
poolManagerExtsloadAbi = parseAbi(["function extsload(bytes32 slot) view returns (bytes32)"]);
|
|
12160
12164
|
multicall3Abi = parseAbi([
|
|
12161
12165
|
"struct Call3 { address target; bool allowFailure; bytes callData; }",
|
|
12162
12166
|
"struct Result { bool success; bytes returnData; }",
|
|
@@ -13673,7 +13677,7 @@ var init_quote = __esm({
|
|
|
13673
13677
|
});
|
|
13674
13678
|
|
|
13675
13679
|
// ../sdk/src/pairs.ts
|
|
13676
|
-
import { getAddress as getAddress9, parseAbi as parseAbi2, zeroAddress as zeroAddress6 } from "viem";
|
|
13680
|
+
import { encodeAbiParameters as encodeAbiParameters5, getAddress as getAddress9, hexToBigInt, keccak256 as keccak2569, parseAbi as parseAbi2, toHex as toHex2, zeroAddress as zeroAddress6 } from "viem";
|
|
13677
13681
|
function findLaunchPair(symbolOrAddress) {
|
|
13678
13682
|
const s = symbolOrAddress.trim();
|
|
13679
13683
|
if (/^0x[0-9a-fA-F]{40}$/.test(s)) {
|
|
@@ -13688,6 +13692,14 @@ function launchPair(symbolOrAddress) {
|
|
|
13688
13692
|
if (q === null) throw new RangeError(`${symbolOrAddress} is not a pair Ostra offers; the pairs are ${LAUNCH_PAIRS.map((x) => x.symbol).join(", ")}`);
|
|
13689
13693
|
return q;
|
|
13690
13694
|
}
|
|
13695
|
+
async function readOstraPool(client) {
|
|
13696
|
+
const slot0 = keccak2569(encodeAbiParameters5([{ type: "bytes32" }, { type: "uint256" }], [OSTRA_POOL_ID, POOLS_SLOT2]));
|
|
13697
|
+
const [word, liq] = await Promise.all([
|
|
13698
|
+
client.readContract({ address: UNISWAP_V4_POOL_MANAGER, abi: poolManagerExtsloadAbi, functionName: "extsload", args: [slot0] }),
|
|
13699
|
+
client.readContract({ address: UNISWAP_V4_POOL_MANAGER, abi: poolManagerExtsloadAbi, functionName: "extsload", args: [toHex2(hexToBigInt(slot0) + LIQUIDITY_OFFSET, { size: 32 })] })
|
|
13700
|
+
]);
|
|
13701
|
+
return { sqrtPriceX96: hexToBigInt(word) & (1n << 160n) - 1n, liquidity: hexToBigInt(liq) & (1n << 128n) - 1n };
|
|
13702
|
+
}
|
|
13691
13703
|
async function readPairUsdPrice(client, quote) {
|
|
13692
13704
|
const block = await client.getBlock();
|
|
13693
13705
|
const now3 = Number(block.timestamp);
|
|
@@ -13710,10 +13722,15 @@ async function readPairUsdPrice(client, quote) {
|
|
|
13710
13722
|
client.readContract({ address: OSTRA_PONS_CURVE, abi: ponsCurveAbi, functionName: "graduated" }),
|
|
13711
13723
|
client.readContract({ address: OSTRA_PONS_CURVE, abi: ponsCurveAbi, functionName: "getReserves" })
|
|
13712
13724
|
]);
|
|
13713
|
-
if (graduated)
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13725
|
+
if (graduated) {
|
|
13726
|
+
const { sqrtPriceX96, liquidity } = await readOstraPool(client);
|
|
13727
|
+
if (sqrtPriceX96 === 0n || liquidity === 0n) throw new Error(`OSTRA's pool ${OSTRA_POOL_ID} has no price or no liquidity in range`);
|
|
13728
|
+
priceE8 = (answer << 192n) / (sqrtPriceX96 * sqrtPriceX96);
|
|
13729
|
+
} else {
|
|
13730
|
+
const [ethReserve, tokenReserve] = reserves;
|
|
13731
|
+
if (ethReserve <= 0n || tokenReserve <= 0n) throw new Error(`the OSTRA Pons curve reports reserves of ${ethReserve} wei and ${tokenReserve} tokens`);
|
|
13732
|
+
priceE8 = answer * ethReserve / tokenReserve;
|
|
13733
|
+
}
|
|
13717
13734
|
if (priceE8 < 100n) throw new Error(`OSTRA's price (${priceE8} x 0.00000001 USD) is too small to set a market cap in within 1%`);
|
|
13718
13735
|
}
|
|
13719
13736
|
if (quote.kind === "stock") {
|
|
@@ -13728,7 +13745,7 @@ function usdToQuoteUnits(usdE6, priceE8, decimals) {
|
|
|
13728
13745
|
if (priceE8 <= 0n) throw new RangeError("the price must be positive");
|
|
13729
13746
|
return usdE6 * 10n ** BigInt(decimals) * 100n / priceE8;
|
|
13730
13747
|
}
|
|
13731
|
-
var STOCK_PRICE_MAX_AGE, ETH_PRICE_MAX_AGE, stock, LAUNCH_PAIRS, stockTokenAbi;
|
|
13748
|
+
var STOCK_PRICE_MAX_AGE, ETH_PRICE_MAX_AGE, stock, LAUNCH_PAIRS, stockTokenAbi, OSTRA_POOL_ID, POOLS_SLOT2, LIQUIDITY_OFFSET;
|
|
13732
13749
|
var init_pairs = __esm({
|
|
13733
13750
|
"../sdk/src/pairs.ts"() {
|
|
13734
13751
|
"use strict";
|
|
@@ -13783,6 +13800,14 @@ var init_pairs = __esm({
|
|
|
13783
13800
|
stock("USO", "United States Oil Fund ETF", "0xa30FA36Db767ad9eD3f7a60fC79526fB4d56D344", "0x75a9c76Ef439e2C7c2E5a34Ab105EcFe3766431c")
|
|
13784
13801
|
];
|
|
13785
13802
|
stockTokenAbi = parseAbi2(["function uiMultiplier() view returns (uint256)"]);
|
|
13803
|
+
OSTRA_POOL_ID = keccak2569(
|
|
13804
|
+
encodeAbiParameters5(
|
|
13805
|
+
[{ type: "address" }, { type: "address" }, { type: "uint24" }, { type: "int24" }, { type: "address" }],
|
|
13806
|
+
[zeroAddress6, OSTRA, OSTRA_POOL_FEE, OSTRA_POOL_TICK_SPACING, PONS_HOOK]
|
|
13807
|
+
)
|
|
13808
|
+
);
|
|
13809
|
+
POOLS_SLOT2 = 6n;
|
|
13810
|
+
LIQUIDITY_OFFSET = 3n;
|
|
13786
13811
|
}
|
|
13787
13812
|
});
|
|
13788
13813
|
|
|
@@ -13813,7 +13838,7 @@ var init_browser = __esm({
|
|
|
13813
13838
|
});
|
|
13814
13839
|
|
|
13815
13840
|
// ../sdk/src/deploy.ts
|
|
13816
|
-
import { concat as concat3, encodeDeployData, encodeFunctionData as encodeFunctionData5, getAddress as getAddress10, getContractAddress as getContractAddress2, keccak256 as
|
|
13841
|
+
import { concat as concat3, encodeDeployData, encodeFunctionData as encodeFunctionData5, getAddress as getAddress10, getContractAddress as getContractAddress2, keccak256 as keccak25610, numberToHex as numberToHex2 } from "viem";
|
|
13817
13842
|
var init_deploy = __esm({
|
|
13818
13843
|
"../sdk/src/deploy.ts"() {
|
|
13819
13844
|
"use strict";
|
|
@@ -13959,6 +13984,132 @@ var init_amount = __esm({
|
|
|
13959
13984
|
}
|
|
13960
13985
|
});
|
|
13961
13986
|
|
|
13987
|
+
// ../core/src/ai.ts
|
|
13988
|
+
import { getAddress as getAddress11 } from "viem";
|
|
13989
|
+
function textStreamAnswer(sse) {
|
|
13990
|
+
let content = "";
|
|
13991
|
+
let reasoning = "";
|
|
13992
|
+
const calls = [];
|
|
13993
|
+
let closing = null;
|
|
13994
|
+
let finish = null;
|
|
13995
|
+
for (const event of sse.split(/\r?\n\r?\n/)) {
|
|
13996
|
+
const lines = event.split(/\r?\n/).filter((l) => l !== "" && !l.startsWith(":"));
|
|
13997
|
+
if (lines.length === 0) continue;
|
|
13998
|
+
const named = lines[0]?.startsWith("event: ") ? lines[0].slice("event: ".length) : null;
|
|
13999
|
+
const data = lines.filter((l) => l.startsWith("data: ")).map((l) => l.slice("data: ".length)).join("\n");
|
|
14000
|
+
if (data === "" || data === "[DONE]") continue;
|
|
14001
|
+
let json;
|
|
14002
|
+
try {
|
|
14003
|
+
json = JSON.parse(data);
|
|
14004
|
+
} catch {
|
|
14005
|
+
continue;
|
|
14006
|
+
}
|
|
14007
|
+
if (named === "ostra" || json.object === "ostra.task") {
|
|
14008
|
+
closing = json;
|
|
14009
|
+
continue;
|
|
14010
|
+
}
|
|
14011
|
+
const choice = json.choices?.[0];
|
|
14012
|
+
if (choice === void 0) continue;
|
|
14013
|
+
if (choice.finish_reason !== null && choice.finish_reason !== void 0) finish = choice.finish_reason;
|
|
14014
|
+
const d = choice.delta ?? {};
|
|
14015
|
+
if (typeof d.content === "string") content += d.content;
|
|
14016
|
+
if (typeof d.reasoning === "string") reasoning += d.reasoning;
|
|
14017
|
+
for (const tc of d.tool_calls ?? []) {
|
|
14018
|
+
const i = typeof tc.index === "number" ? tc.index : 0;
|
|
14019
|
+
const cur = calls[i] ?? (calls[i] = { type: "function", function: { name: "", arguments: "" } });
|
|
14020
|
+
if (typeof tc.id === "string") cur.id = tc.id;
|
|
14021
|
+
if (typeof tc.type === "string") cur.type = tc.type;
|
|
14022
|
+
if (typeof tc.function?.name === "string") cur.function.name += tc.function.name;
|
|
14023
|
+
if (typeof tc.function?.arguments === "string") cur.function.arguments += tc.function.arguments;
|
|
14024
|
+
}
|
|
14025
|
+
}
|
|
14026
|
+
const message = { role: "assistant", content, reasoning: reasoning === "" ? null : reasoning, ...calls.length === 0 ? {} : { tool_calls: calls.filter((c) => c !== void 0) } };
|
|
14027
|
+
if (closing === null) return { error: "stream_incomplete", message: "the answer's stream ended before what it was charged was told", partial: message };
|
|
14028
|
+
const { object: _object, ...rest } = closing;
|
|
14029
|
+
if (typeof rest.error === "string") return { ...rest, partial: message };
|
|
14030
|
+
return { ...rest, message, finish_reason: rest.finish_reason ?? finish };
|
|
14031
|
+
}
|
|
14032
|
+
var AI_TASK_KINDS, AI_MAX_BODY_CHARS, SET_HERE, REQUEST_TIMEOUT_MS, TASK_TIMEOUT_MS, RAW_ANSWER_CHARS, AiService;
|
|
14033
|
+
var init_ai = __esm({
|
|
14034
|
+
"../core/src/ai.ts"() {
|
|
14035
|
+
"use strict";
|
|
14036
|
+
init_define_OSTRA_PACKAGED();
|
|
14037
|
+
init_amount();
|
|
14038
|
+
AI_TASK_KINDS = ["text", "image", "video"];
|
|
14039
|
+
AI_MAX_BODY_CHARS = 48 * 1024 * 1024;
|
|
14040
|
+
SET_HERE = ["task", "max_price", "payer", "stream"];
|
|
14041
|
+
REQUEST_TIMEOUT_MS = 6e4;
|
|
14042
|
+
TASK_TIMEOUT_MS = 66e4;
|
|
14043
|
+
RAW_ANSWER_CHARS = 4e3;
|
|
14044
|
+
AiService = class {
|
|
14045
|
+
#url;
|
|
14046
|
+
#payments;
|
|
14047
|
+
#vault;
|
|
14048
|
+
constructor(config, payments, vault) {
|
|
14049
|
+
if (config.aiUrl === null) throw new Error("Ostra AI is not configured here (OSTRA_AI_URL)");
|
|
14050
|
+
this.#url = config.aiUrl.replace(/\/+$/, "");
|
|
14051
|
+
this.#payments = payments;
|
|
14052
|
+
this.#vault = vault;
|
|
14053
|
+
}
|
|
14054
|
+
/** Runs a `kind` task with `request`'s parameters, paying at most `maxPrice` USDG from a channel of the vault. */
|
|
14055
|
+
async task(kind, request, maxPrice, deposit) {
|
|
14056
|
+
if (!AI_TASK_KINDS.includes(kind)) throw new RangeError(`the task is one of ${AI_TASK_KINDS.join(", ")}`);
|
|
14057
|
+
for (const key of SET_HERE) if (key in request) throw new RangeError(`${key} is set by ostra_ai: leave it out of request`);
|
|
14058
|
+
const units2 = parseTokenAmount(maxPrice);
|
|
14059
|
+
if (units2 <= 0n) throw new RangeError("maxPrice must be positive");
|
|
14060
|
+
const payer = getAddress11(await this.#vault.vaultAddress());
|
|
14061
|
+
const body = JSON.stringify({ ...request, task: kind, max_price: units2.toString(), payer, ...kind === "text" ? { stream: true } : {} });
|
|
14062
|
+
const r = await this.#payments.pay({
|
|
14063
|
+
url: `${this.#url}/v1/ai/${kind}`,
|
|
14064
|
+
method: "POST",
|
|
14065
|
+
headers: { "content-type": "application/json" },
|
|
14066
|
+
body,
|
|
14067
|
+
maxPrice,
|
|
14068
|
+
maxBodyChars: AI_MAX_BODY_CHARS,
|
|
14069
|
+
timeoutMs: TASK_TIMEOUT_MS,
|
|
14070
|
+
...deposit === void 0 ? {} : { deposit }
|
|
14071
|
+
});
|
|
14072
|
+
let answer;
|
|
14073
|
+
const head = r.body.trimStart();
|
|
14074
|
+
if (r.status === 200 && kind === "text" && (head.startsWith("data:") || head.startsWith(":") || head.startsWith("event:"))) answer = textStreamAnswer(r.body);
|
|
14075
|
+
else {
|
|
14076
|
+
try {
|
|
14077
|
+
answer = JSON.parse(r.body);
|
|
14078
|
+
} catch {
|
|
14079
|
+
answer = r.body.slice(0, RAW_ANSWER_CHARS);
|
|
14080
|
+
}
|
|
14081
|
+
}
|
|
14082
|
+
const failed = answer !== null && typeof answer === "object" && typeof answer.error === "string";
|
|
14083
|
+
const notes = [r.note, r.truncated ? "the answer was longer than ostra_ai reads and was cut" : void 0, r.status === 200 && failed ? "the task failed after it began (answer.error): what it was charged is the vault's credit with Ostra AI" : void 0].filter((x) => x !== void 0);
|
|
14084
|
+
return { status: r.status, paid: r.paid, channel: r.channel, channelLeft: r.channelLeft, answer, ...notes.length === 0 ? {} : { note: notes.join("; ") } };
|
|
14085
|
+
}
|
|
14086
|
+
/** A video job's status; the first final one settles its cost and credits the rest. */
|
|
14087
|
+
async job(id) {
|
|
14088
|
+
if (!/^[0-9a-f]{32}$/.test(id)) throw new RangeError("job is the 32 hex characters ostra_ai gave");
|
|
14089
|
+
const res = await fetch(`${this.#url}/v1/ai/video/${id}`, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
14090
|
+
const text2 = await res.text();
|
|
14091
|
+
try {
|
|
14092
|
+
return { status: res.status, answer: JSON.parse(text2) };
|
|
14093
|
+
} catch {
|
|
14094
|
+
return { status: res.status, answer: text2.slice(0, 2e3) };
|
|
14095
|
+
}
|
|
14096
|
+
}
|
|
14097
|
+
/** Where a finished video job's content is read (no payment). */
|
|
14098
|
+
contentUrl(id) {
|
|
14099
|
+
if (!/^[0-9a-f]{32}$/.test(id)) throw new RangeError("job is the 32 hex characters ostra_ai gave");
|
|
14100
|
+
return `${this.#url}/v1/ai/video/${id}/content`;
|
|
14101
|
+
}
|
|
14102
|
+
/** The vault's credit with Ostra AI (USDG base units). */
|
|
14103
|
+
async credit() {
|
|
14104
|
+
const payer = getAddress11(await this.#vault.vaultAddress());
|
|
14105
|
+
const res = await fetch(`${this.#url}/v1/ai/credits/${payer}`, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
14106
|
+
if (!res.ok) throw new Error(`Ostra AI answered ${res.status} for the vault's credit`);
|
|
14107
|
+
return res.json();
|
|
14108
|
+
}
|
|
14109
|
+
};
|
|
14110
|
+
}
|
|
14111
|
+
});
|
|
14112
|
+
|
|
13962
14113
|
// ../core/src/chain.ts
|
|
13963
14114
|
import { createWalletClient } from "viem";
|
|
13964
14115
|
function tokenBalance(client, token, owner) {
|
|
@@ -14053,13 +14204,13 @@ var init_config = __esm({
|
|
|
14053
14204
|
});
|
|
14054
14205
|
|
|
14055
14206
|
// ../core/src/relay.ts
|
|
14056
|
-
import { decodeFunctionData as decodeFunctionData3, getAddress as
|
|
14207
|
+
import { decodeFunctionData as decodeFunctionData3, getAddress as getAddress12, isAddress as isAddress5 } from "viem";
|
|
14057
14208
|
import { x402Client, x402HTTPClient } from "@x402/core/client";
|
|
14058
14209
|
import { toClientEvmSigner } from "@x402/evm";
|
|
14059
14210
|
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client";
|
|
14060
14211
|
function address(value, what) {
|
|
14061
14212
|
if (typeof value !== "string" || !isAddress5(value, { strict: false })) throw new Error(`${what} is not an address`);
|
|
14062
|
-
return
|
|
14213
|
+
return getAddress12(value);
|
|
14063
14214
|
}
|
|
14064
14215
|
function checkSplits(raw, what) {
|
|
14065
14216
|
if (!Array.isArray(raw)) throw new Error(`${what} are not a list`);
|
|
@@ -14080,7 +14231,7 @@ function checkRelayerFacts(raw, want) {
|
|
|
14080
14231
|
const f = raw;
|
|
14081
14232
|
if (f === null || typeof f !== "object") throw new Error("the relayer's terms are not an object");
|
|
14082
14233
|
if (f.chainId !== want.chainId) throw new Error(`the relayer serves chain ${String(f.chainId)}, not ${want.chainId}`);
|
|
14083
|
-
if (address(f.token, "the relayer's token") !==
|
|
14234
|
+
if (address(f.token, "the relayer's token") !== getAddress12(want.token)) throw new Error(`the relayer serves token ${String(f.token)}, not ${want.token}`);
|
|
14084
14235
|
if (f.decimals !== TOKEN_DECIMALS) throw new Error(`the relayer's token has ${String(f.decimals)} decimals, not ${TOKEN_DECIMALS}`);
|
|
14085
14236
|
if (address(f.priceFeed, "the relayer's price feed") !== CHAINLINK_ETH_USD) throw new Error(`the relayer prices from ${String(f.priceFeed)}, not the Chainlink ETH/USD feed ${CHAINLINK_ETH_USD}`);
|
|
14086
14237
|
if (f.maxCalls !== MAX_RELAY_CALLS) throw new Error(`the relayer takes ${String(f.maxCalls)} calls per request, not ${MAX_RELAY_CALLS}`);
|
|
@@ -14108,10 +14259,10 @@ function relayerChannelDeposit(needed, vaultBalance, keep = 0n) {
|
|
|
14108
14259
|
function relayerOfferProblem(r, want) {
|
|
14109
14260
|
if (r.scheme !== "batch-settlement") return `the offer is ${r.scheme}, not batch-settlement`;
|
|
14110
14261
|
if (r.network !== want.network) return `the offer is on ${r.network}, not ${want.network}`;
|
|
14111
|
-
if (!isAddress5(r.asset, { strict: false }) ||
|
|
14112
|
-
if (!isAddress5(r.payTo, { strict: false }) ||
|
|
14262
|
+
if (!isAddress5(r.asset, { strict: false }) || getAddress12(r.asset) !== getAddress12(want.config.token)) return `the offer is in ${r.asset}, not ${want.config.token}`;
|
|
14263
|
+
if (!isAddress5(r.payTo, { strict: false }) || getAddress12(r.payTo) !== getAddress12(want.config.receiver)) return `the offer pays ${r.payTo}, not the relayer's split ${want.config.receiver}`;
|
|
14113
14264
|
const extra = r.extra ?? {};
|
|
14114
|
-
if (typeof extra.receiverAuthorizer !== "string" || !isAddress5(extra.receiverAuthorizer, { strict: false }) ||
|
|
14265
|
+
if (typeof extra.receiverAuthorizer !== "string" || !isAddress5(extra.receiverAuthorizer, { strict: false }) || getAddress12(extra.receiverAuthorizer) !== getAddress12(want.config.receiverAuthorizer)) {
|
|
14115
14266
|
return `the offer's receiverAuthorizer is ${String(extra.receiverAuthorizer)}, not the relayer's vault ${want.config.receiverAuthorizer}`;
|
|
14116
14267
|
}
|
|
14117
14268
|
if (extra.withdrawDelay !== want.config.withdrawDelay) return `the offer's withdrawDelay is ${String(extra.withdrawDelay)}, not the relayer's ${want.config.withdrawDelay} s`;
|
|
@@ -14124,7 +14275,7 @@ function relayerOfferProblem(r, want) {
|
|
|
14124
14275
|
}
|
|
14125
14276
|
function openChannelCall(calls, vault, token) {
|
|
14126
14277
|
for (const c of calls) {
|
|
14127
|
-
if (
|
|
14278
|
+
if (getAddress12(c.to) !== getAddress12(vault)) continue;
|
|
14128
14279
|
let decoded;
|
|
14129
14280
|
try {
|
|
14130
14281
|
decoded = decodeFunctionData3({ abi: ostraVaultAbi, data: c.data });
|
|
@@ -14139,7 +14290,7 @@ function openChannelCall(calls, vault, token) {
|
|
|
14139
14290
|
}
|
|
14140
14291
|
return null;
|
|
14141
14292
|
}
|
|
14142
|
-
var RELAYER_DIR, VAULT_SPEND_GAS,
|
|
14293
|
+
var RELAYER_DIR, VAULT_SPEND_GAS, REQUEST_TIMEOUT_MS2, MAX_STEPS, MAX_RESENDS, LANDED_TIMEOUT_MS, OPEN_READ_TRIES, OPEN_READ_INTERVAL_MS, BPS_DENOMINATOR, now, LocalSender, RelayerUnavailableError, PendingSpendUnpaidError, RelayerError, RelayerStore, RelayerClient;
|
|
14143
14294
|
var init_relay = __esm({
|
|
14144
14295
|
"../core/src/relay.ts"() {
|
|
14145
14296
|
"use strict";
|
|
@@ -14150,7 +14301,7 @@ var init_relay = __esm({
|
|
|
14150
14301
|
init_config();
|
|
14151
14302
|
RELAYER_DIR = "relayer";
|
|
14152
14303
|
VAULT_SPEND_GAS = 400000n;
|
|
14153
|
-
|
|
14304
|
+
REQUEST_TIMEOUT_MS2 = 24e4;
|
|
14154
14305
|
MAX_STEPS = 8;
|
|
14155
14306
|
MAX_RESENDS = 3;
|
|
14156
14307
|
LANDED_TIMEOUT_MS = 6e4;
|
|
@@ -14210,7 +14361,7 @@ var init_relay = __esm({
|
|
|
14210
14361
|
#name;
|
|
14211
14362
|
constructor(agentFolder, chainId, token, relayerVault) {
|
|
14212
14363
|
this.#folder = agentFolder.folder(RELAYER_DIR);
|
|
14213
|
-
this.#name = `${chainId}-${
|
|
14364
|
+
this.#name = `${chainId}-${getAddress12(token)}-${getAddress12(relayerVault)}.json`;
|
|
14214
14365
|
}
|
|
14215
14366
|
async load() {
|
|
14216
14367
|
const text2 = await this.#folder.read(this.#name);
|
|
@@ -14264,7 +14415,7 @@ var init_relay = __esm({
|
|
|
14264
14415
|
method,
|
|
14265
14416
|
headers: body === void 0 ? headers : { "content-type": "application/json", ...headers },
|
|
14266
14417
|
...body === void 0 ? {} : { body },
|
|
14267
|
-
signal: AbortSignal.timeout(
|
|
14418
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
14268
14419
|
});
|
|
14269
14420
|
} catch (err) {
|
|
14270
14421
|
throw new RelayerUnavailableError(`the relayer at ${this.url} cannot be reached: ${err.message}`);
|
|
@@ -14295,7 +14446,7 @@ var init_relay = __esm({
|
|
|
14295
14446
|
functionName: "splitAddress",
|
|
14296
14447
|
args: [d.token, facts.vault, facts.splits.map((s) => s.recipient), facts.splits.map((s) => s.bps)]
|
|
14297
14448
|
});
|
|
14298
|
-
if (
|
|
14449
|
+
if (getAddress12(split) !== facts.split) throw new Error(`the relayer's split ${facts.split} is not the OstraSplit of its vault and splits (${split})`);
|
|
14299
14450
|
this.#facts = facts;
|
|
14300
14451
|
this.#store = new RelayerStore(this.#keys.folder, this.#config.chainId, d.token, facts.vault);
|
|
14301
14452
|
return facts;
|
|
@@ -14317,7 +14468,7 @@ var init_relay = __esm({
|
|
|
14317
14468
|
channel: String(open3.channel).toLowerCase(),
|
|
14318
14469
|
amount: BigInt(String(open3.amount)),
|
|
14319
14470
|
txHash: String(open3.txHash),
|
|
14320
|
-
calls: Array.isArray(open3.calls) ? open3.calls.map((c) => ({ to:
|
|
14471
|
+
calls: Array.isArray(open3.calls) ? open3.calls.map((c) => ({ to: getAddress12(c.to), data: c.data })) : []
|
|
14321
14472
|
}
|
|
14322
14473
|
};
|
|
14323
14474
|
}
|
|
@@ -14371,7 +14522,7 @@ var init_relay = __esm({
|
|
|
14371
14522
|
continue;
|
|
14372
14523
|
}
|
|
14373
14524
|
const ch = await readChannel(this.#client, this.#config.deployment.batchSettlement, c.channel);
|
|
14374
|
-
const usable = payer !== null &&
|
|
14525
|
+
const usable = payer !== null && getAddress12(c.config.payer) === payer && getAddress12(c.config.receiverAuthorizer) === facts.vault && getAddress12(c.config.receiver) === facts.split && ch.pendingWithdrawal === null && ch.balance - BigInt(c.cumulative) >= amount;
|
|
14375
14526
|
if (!usable) {
|
|
14376
14527
|
c.retired = true;
|
|
14377
14528
|
await this.#save();
|
|
@@ -14439,7 +14590,7 @@ var init_relay = __esm({
|
|
|
14439
14590
|
else this.#reserved.delete(reservation.channel);
|
|
14440
14591
|
}
|
|
14441
14592
|
async #post(calls, extra, headers = {}) {
|
|
14442
|
-
const body = { calls: calls.map((c) => ({ to:
|
|
14593
|
+
const body = { calls: calls.map((c) => ({ to: getAddress12(c.to), data: c.data })) };
|
|
14443
14594
|
if (extra.prepay === true) body.prepay = true;
|
|
14444
14595
|
if (extra.payer !== null) body.payer = extra.payer;
|
|
14445
14596
|
if (extra.allowFailedSwaps === true) body.allowFailedSwaps = true;
|
|
@@ -14448,10 +14599,10 @@ var init_relay = __esm({
|
|
|
14448
14599
|
/** The x402 HTTP client of relayer channel `c`: the stock batch-settlement client, the vault as payer, the channel's voucher key signing, never depositing. */
|
|
14449
14600
|
#x402(c) {
|
|
14450
14601
|
const voucherKey = this.#keys.channelVoucherSigner(this.#config.chainId, this.#config.deployment.token, c.config.salt);
|
|
14451
|
-
if (voucherKey.address !==
|
|
14602
|
+
if (voucherKey.address !== getAddress12(c.config.payerAuthorizer)) throw new Error(`the voucher key of relayer channel ${c.channel} is not derived from this machine's master seed`);
|
|
14452
14603
|
const client = this.#client;
|
|
14453
14604
|
const payer = {
|
|
14454
|
-
address:
|
|
14605
|
+
address: getAddress12(c.config.payer),
|
|
14455
14606
|
signTypedData: () => Promise.reject(new Error("a vault never signs typed data")),
|
|
14456
14607
|
readContract: (args) => client.readContract(args)
|
|
14457
14608
|
};
|
|
@@ -14543,11 +14694,11 @@ var init_relay = __esm({
|
|
|
14543
14694
|
const config = found.config;
|
|
14544
14695
|
const id = channelId(config, this.#config.chainId, d.batchSettlement).toLowerCase();
|
|
14545
14696
|
if (id !== channel.toLowerCase()) throw new Error(`the relayer reports channel ${channel}, but the open in the request is channel ${id}`);
|
|
14546
|
-
if (
|
|
14697
|
+
if (getAddress12(config.receiver) !== facts.split || getAddress12(config.receiverAuthorizer) !== facts.vault || config.withdrawDelay !== facts.gracePeriodSeconds) {
|
|
14547
14698
|
throw new Error(`channel ${channel} is not on the relayer's terms`);
|
|
14548
14699
|
}
|
|
14549
14700
|
const voucherKey = this.#keys.channelVoucherSigner(this.#config.chainId, d.token, config.salt);
|
|
14550
|
-
if (voucherKey.address !==
|
|
14701
|
+
if (voucherKey.address !== getAddress12(config.payerAuthorizer)) throw new Error(`the voucher key of relayer channel ${channel} is not derived from this machine's master seed`);
|
|
14551
14702
|
const ch = await this.#openedChannel(id, openTx);
|
|
14552
14703
|
if (ch.balance !== found.amount || ch.pendingWithdrawal !== null) throw new Error(`relayer channel ${channel} does not hold its deposit of ${found.amount}`);
|
|
14553
14704
|
const most = debt + await this.#spendBound();
|
|
@@ -14702,7 +14853,7 @@ var init_relay = __esm({
|
|
|
14702
14853
|
});
|
|
14703
14854
|
|
|
14704
14855
|
// ../core/src/channels.ts
|
|
14705
|
-
import { bytesToHex as bytesToHex7, decodeFunctionData as decodeFunctionData4, encodeFunctionData as encodeFunctionData6, getAddress as
|
|
14856
|
+
import { bytesToHex as bytesToHex7, decodeFunctionData as decodeFunctionData4, encodeFunctionData as encodeFunctionData6, getAddress as getAddress13, isAddress as isAddress6, parseAbiItem } from "viem";
|
|
14706
14857
|
async function channelOpenedLogs(client, vault, channel, fromBlock, toBlock) {
|
|
14707
14858
|
const out = [];
|
|
14708
14859
|
for (let from = fromBlock; from <= toBlock; from += LOG_WINDOW_BLOCKS) {
|
|
@@ -14718,7 +14869,7 @@ function parseRecipients(input) {
|
|
|
14718
14869
|
const out = [];
|
|
14719
14870
|
for (const r of input) {
|
|
14720
14871
|
if (!isAddress6(r.recipient, { strict: false })) throw new RangeError(`${r.recipient} is not an address`);
|
|
14721
|
-
const recipient =
|
|
14872
|
+
const recipient = getAddress13(r.recipient);
|
|
14722
14873
|
if (BigInt(recipient) === 0n) throw new RangeError("a recipient must not be the zero address");
|
|
14723
14874
|
if (!Number.isInteger(r.bps) || r.bps < 1 || r.bps > BPS_DENOMINATOR2) throw new RangeError(`the bps of ${recipient} must be an integer from 1 to ${BPS_DENOMINATOR2}`);
|
|
14724
14875
|
if (seen.has(recipient)) throw new RangeError(`${recipient} is listed twice`);
|
|
@@ -14737,7 +14888,7 @@ function parseGracePeriod(seconds) {
|
|
|
14737
14888
|
}
|
|
14738
14889
|
async function splitAddress(client, config, vault, recipients) {
|
|
14739
14890
|
const d = config.deployment;
|
|
14740
|
-
return
|
|
14891
|
+
return getAddress13(
|
|
14741
14892
|
await client.readContract({
|
|
14742
14893
|
address: d.splitFactory,
|
|
14743
14894
|
abi: ostraSplitFactoryAbi,
|
|
@@ -14771,12 +14922,12 @@ async function recoverChannelConfig(client, config, vault, channel) {
|
|
|
14771
14922
|
if (log2.transactionHash === null) continue;
|
|
14772
14923
|
const tx = await client.getTransaction({ hash: log2.transactionHash });
|
|
14773
14924
|
const calls = [];
|
|
14774
|
-
if (tx.to !== null && tx.to !== void 0 &&
|
|
14775
|
-
if (tx.to !== null && tx.to !== void 0 &&
|
|
14925
|
+
if (tx.to !== null && tx.to !== void 0 && getAddress13(tx.to) === getAddress13(vault)) calls.push({ to: vault, data: tx.input });
|
|
14926
|
+
if (tx.to !== null && tx.to !== void 0 && getAddress13(tx.to) === MULTICALL3) {
|
|
14776
14927
|
try {
|
|
14777
14928
|
const decoded = decodeFunctionData4({ abi: multicall3Abi, data: tx.input });
|
|
14778
14929
|
const inner = decoded.args[0];
|
|
14779
|
-
for (const c of inner) if (
|
|
14930
|
+
for (const c of inner) if (getAddress13(c.target) === getAddress13(vault)) calls.push({ to: vault, data: c.callData });
|
|
14780
14931
|
} catch {
|
|
14781
14932
|
}
|
|
14782
14933
|
}
|
|
@@ -14856,7 +15007,7 @@ var init_channels = __esm({
|
|
|
14856
15007
|
const text2 = await this.#folder.read(name);
|
|
14857
15008
|
if (text2 === void 0) continue;
|
|
14858
15009
|
const record = this.#check(JSON.parse(text2), name);
|
|
14859
|
-
if (record.chainId === chainId &&
|
|
15010
|
+
if (record.chainId === chainId && getAddress13(record.token) === getAddress13(token)) out.push(record);
|
|
14860
15011
|
}
|
|
14861
15012
|
return out.sort((x, y) => x.createdAt - y.createdAt);
|
|
14862
15013
|
}
|
|
@@ -14904,8 +15055,8 @@ var init_channels = __esm({
|
|
|
14904
15055
|
vault,
|
|
14905
15056
|
channel: opening.channel,
|
|
14906
15057
|
config: opening.config,
|
|
14907
|
-
payee:
|
|
14908
|
-
voucherKey:
|
|
15058
|
+
payee: getAddress13(o.receiverAuthorizer),
|
|
15059
|
+
voucherKey: getAddress13(o.payerAuthorizer),
|
|
14909
15060
|
deposit: o.amount.toString(),
|
|
14910
15061
|
gracePeriod: o.withdrawDelay,
|
|
14911
15062
|
recipients,
|
|
@@ -14941,7 +15092,7 @@ var init_channels = __esm({
|
|
|
14941
15092
|
open(input) {
|
|
14942
15093
|
return this.#serial(async () => {
|
|
14943
15094
|
if (!isAddress6(input.payee, { strict: false })) throw new RangeError(`${input.payee} is not an address`);
|
|
14944
|
-
const payee =
|
|
15095
|
+
const payee = getAddress13(input.payee);
|
|
14945
15096
|
const deposit = parseTokenAmount(input.deposit);
|
|
14946
15097
|
if (deposit === 0n) throw new RangeError("deposit must be greater than zero");
|
|
14947
15098
|
const gracePeriod = parseGracePeriod(input.gracePeriod);
|
|
@@ -14950,8 +15101,8 @@ var init_channels = __esm({
|
|
|
14950
15101
|
if (payeeVault === null) throw new Error(`${payee} is not an Ostra vault; open_channel pays Ostra vaults only (pay other sellers with pay)`);
|
|
14951
15102
|
if (payeeVault.token !== this.#token()) throw new Error(`the payee vault holds ${payeeVault.token}, not ${this.#token()}`);
|
|
14952
15103
|
if (input.receiver !== void 0 && recipients.length !== 0) throw new RangeError("a channel names its receiver or the recipients its split is derived from, not both");
|
|
14953
|
-
const receiver = input.receiver !== void 0 ?
|
|
14954
|
-
if (receiver ===
|
|
15104
|
+
const receiver = input.receiver !== void 0 ? getAddress13(input.receiver) : await splitAddress(this.#client, this.#config, payee, recipients);
|
|
15105
|
+
if (receiver === getAddress13("0x0000000000000000000000000000000000000000")) throw new RangeError("the receiver must not be the zero address");
|
|
14955
15106
|
const salt = randomSalt();
|
|
14956
15107
|
const voucher = this.#keys.channelVoucherSigner(this.#config.chainId, this.#token(), salt);
|
|
14957
15108
|
const open3 = { payerAuthorizer: voucher.address, receiver, receiverAuthorizer: payee, withdrawDelay: gracePeriod, salt, amount: deposit };
|
|
@@ -14995,7 +15146,7 @@ var init_channels = __esm({
|
|
|
14995
15146
|
const view2 = {
|
|
14996
15147
|
channel: record.channel,
|
|
14997
15148
|
payee: record.payee,
|
|
14998
|
-
receiver:
|
|
15149
|
+
receiver: getAddress13(record.config.receiver),
|
|
14999
15150
|
gracePeriod: record.gracePeriod,
|
|
15000
15151
|
voucherKey: record.voucherKey,
|
|
15001
15152
|
closeRequested: record.closeRequested,
|
|
@@ -15032,11 +15183,11 @@ var init_channels = __esm({
|
|
|
15032
15183
|
const cfg = config ?? await recoverChannelConfig(this.#client, this.#config, vault, channel);
|
|
15033
15184
|
if (cfg === null) throw new Error(`channel ${channel} was not opened by this agent's vault`);
|
|
15034
15185
|
const d = this.#config.deployment;
|
|
15035
|
-
if (channelId(cfg, this.#config.chainId, d.batchSettlement).toLowerCase() !== channel ||
|
|
15186
|
+
if (channelId(cfg, this.#config.chainId, d.batchSettlement).toLowerCase() !== channel || getAddress13(cfg.payer) !== vault || getAddress13(cfg.token) !== d.token) {
|
|
15036
15187
|
throw new Error(`channel ${channel} was not opened by this agent's vault`);
|
|
15037
15188
|
}
|
|
15038
15189
|
const voucher = this.#keys.channelVoucherSigner(this.#config.chainId, d.token, cfg.salt);
|
|
15039
|
-
if (voucher.address !==
|
|
15190
|
+
if (voucher.address !== getAddress13(cfg.payerAuthorizer)) throw new Error(`channel ${channel} uses a voucher key this machine cannot derive`);
|
|
15040
15191
|
const ch = await this.#read(channel);
|
|
15041
15192
|
const open3 = {
|
|
15042
15193
|
payerAuthorizer: cfg.payerAuthorizer,
|
|
@@ -15114,7 +15265,7 @@ var init_channels = __esm({
|
|
|
15114
15265
|
sent,
|
|
15115
15266
|
...extra
|
|
15116
15267
|
});
|
|
15117
|
-
if (
|
|
15268
|
+
if (getAddress13(record.config.payer) !== getAddress13(record.vault)) throw new Error(`channel ${channel} does not belong to this vault's record`);
|
|
15118
15269
|
for (let i = 0; i < MAX_STEPS_PER_CALL; i++) {
|
|
15119
15270
|
const ch = await this.#read(channel);
|
|
15120
15271
|
const status = channelStatus(ch);
|
|
@@ -15129,7 +15280,7 @@ var init_channels = __esm({
|
|
|
15129
15280
|
try {
|
|
15130
15281
|
if (status === "open") {
|
|
15131
15282
|
const voucher = this.voucherSigner(record);
|
|
15132
|
-
if (voucher.address !==
|
|
15283
|
+
if (voucher.address !== getAddress13(record.config.payerAuthorizer)) throw new Error(`the voucher key of channel ${channel} could not be derived`);
|
|
15133
15284
|
const amount = ch.balance - ch.totalClaimed;
|
|
15134
15285
|
const closeNonce = await this.#client.readContract({ address: record.vault, abi: ostraVaultAbi, functionName: "closeNonce", args: [channel] });
|
|
15135
15286
|
const deadline = await chainTime(this.#client) + CLOSE_REQUEST_TTL_SECONDS;
|
|
@@ -15319,14 +15470,14 @@ var init_passkey = __esm({
|
|
|
15319
15470
|
});
|
|
15320
15471
|
|
|
15321
15472
|
// ../core/src/keys.ts
|
|
15322
|
-
import { bytesToHex as bytesToHex9, getAddress as
|
|
15473
|
+
import { bytesToHex as bytesToHex9, getAddress as getAddress14, hexToBytes as hexToBytes7 } from "viem";
|
|
15323
15474
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
15324
15475
|
function chainBytes(chainId) {
|
|
15325
15476
|
if (!Number.isSafeInteger(chainId) || chainId <= 0) throw new RangeError("chainId must be a positive integer");
|
|
15326
15477
|
return hexToBytes7(`0x${BigInt(chainId).toString(16).padStart(64, "0")}`);
|
|
15327
15478
|
}
|
|
15328
15479
|
function tokenBytes(token) {
|
|
15329
|
-
return hexToBytes7(
|
|
15480
|
+
return hexToBytes7(getAddress14(token));
|
|
15330
15481
|
}
|
|
15331
15482
|
function u64Be(value) {
|
|
15332
15483
|
if (value < 0n || value > U64_MAX5) throw new RangeError("index out of range");
|
|
@@ -15419,7 +15570,7 @@ var init_keys = __esm({
|
|
|
15419
15570
|
* payer and the WOTS store stay the agent's.
|
|
15420
15571
|
*/
|
|
15421
15572
|
async forPrivateVault(chainId, token, index) {
|
|
15422
|
-
const folder = this.#root.folder(PRIVATE_DIR).folder(`${chainId}-${
|
|
15573
|
+
const folder = this.#root.folder(PRIVATE_DIR).folder(`${chainId}-${getAddress14(token)}-${index}`);
|
|
15423
15574
|
await folder.ensure();
|
|
15424
15575
|
return new _Keys({ master: this.#master, feePayer: this.feePayer, store: this.store, folder, root: this.#root, backupExported: this.#backupExported, escrow: this.escrow });
|
|
15425
15576
|
}
|
|
@@ -15430,7 +15581,7 @@ var init_keys = __esm({
|
|
|
15430
15581
|
* agent's folder (ShieldService takes the agent's keys).
|
|
15431
15582
|
*/
|
|
15432
15583
|
async forCreatorVault(chainId, token) {
|
|
15433
|
-
const folder = this.#root.folder(CREATOR_DIR).folder(`${chainId}-${
|
|
15584
|
+
const folder = this.#root.folder(CREATOR_DIR).folder(`${chainId}-${getAddress14(token)}`);
|
|
15434
15585
|
await folder.ensure();
|
|
15435
15586
|
return new _Keys({ master: this.#master, feePayer: this.feePayer, store: this.store, folder, root: this.#root, backupExported: this.#backupExported, escrow: this.escrow });
|
|
15436
15587
|
}
|
|
@@ -15528,13 +15679,13 @@ var init_keys = __esm({
|
|
|
15528
15679
|
});
|
|
15529
15680
|
|
|
15530
15681
|
// ../core/src/pools.ts
|
|
15531
|
-
import { getAddress as
|
|
15682
|
+
import { getAddress as getAddress15, isAddress as isAddress7, zeroAddress as zeroAddress7 } from "viem";
|
|
15532
15683
|
function iso(seconds) {
|
|
15533
15684
|
return new Date(Number(seconds) * 1e3).toISOString();
|
|
15534
15685
|
}
|
|
15535
15686
|
function launchedTokenAddress(text2, what = "token") {
|
|
15536
15687
|
if (!isAddress7(text2, { strict: false })) throw new RangeError(`${what} ${text2} is not an address`);
|
|
15537
|
-
return
|
|
15688
|
+
return getAddress15(text2);
|
|
15538
15689
|
}
|
|
15539
15690
|
async function readLaunchedPool(client, lp, tokenText) {
|
|
15540
15691
|
const token = launchedTokenAddress(tokenText);
|
|
@@ -15547,7 +15698,7 @@ async function readLaunchedPool(client, lp, tokenText) {
|
|
|
15547
15698
|
return { token, id, key, config };
|
|
15548
15699
|
}
|
|
15549
15700
|
function quoteOfPool(pool) {
|
|
15550
|
-
return
|
|
15701
|
+
return getAddress15(pool.config.tokenIs0 ? pool.key.currency1 : pool.key.currency0);
|
|
15551
15702
|
}
|
|
15552
15703
|
async function readPoolView(client, lp, tokenText) {
|
|
15553
15704
|
const pool = await readLaunchedPool(client, lp, tokenText);
|
|
@@ -15581,7 +15732,7 @@ async function readPoolView(client, lp, tokenText) {
|
|
|
15581
15732
|
name,
|
|
15582
15733
|
symbol,
|
|
15583
15734
|
quote,
|
|
15584
|
-
creatorVault:
|
|
15735
|
+
creatorVault: getAddress15(c.creatorVault),
|
|
15585
15736
|
graduated: state.graduated,
|
|
15586
15737
|
tokensSold: formatUnitsAmount(state.tokensSold < 0n ? 0n : state.tokensSold, 18),
|
|
15587
15738
|
quoteRaised: fmtQuote(state.quoteRaised),
|
|
@@ -15593,7 +15744,7 @@ async function readPoolView(client, lp, tokenText) {
|
|
|
15593
15744
|
sellTaxBps: Number(rates[1]),
|
|
15594
15745
|
antiSnipeBps: Number(rates[2]),
|
|
15595
15746
|
maxBuy: c.maxBuy === 0n ? null : formatUnitsAmount(c.maxBuy, 18),
|
|
15596
|
-
dividendToken:
|
|
15747
|
+
dividendToken: getAddress15(c.dividendToken) === zeroAddress7 ? null : getAddress15(c.dividendToken),
|
|
15597
15748
|
launchedAt: iso(BigInt(c.launchedAt)),
|
|
15598
15749
|
airdrop: {
|
|
15599
15750
|
round: round.number,
|
|
@@ -15604,7 +15755,7 @@ async function readPoolView(client, lp, tokenText) {
|
|
|
15604
15755
|
available: formatUnitsAmount(available, 18),
|
|
15605
15756
|
nextRoundAmount: formatUnitsAmount(nextAmount, 18)
|
|
15606
15757
|
},
|
|
15607
|
-
creatorShares: shares[0].map((recipient, i) => ({ recipient:
|
|
15758
|
+
creatorShares: shares[0].map((recipient, i) => ({ recipient: getAddress15(recipient), bps: Number(shares[1][i]) })),
|
|
15608
15759
|
rules: {
|
|
15609
15760
|
quoteDecimals,
|
|
15610
15761
|
supply: formatUnitsAmount(state.supply, 18),
|
|
@@ -15777,7 +15928,7 @@ var init_pending = __esm({
|
|
|
15777
15928
|
});
|
|
15778
15929
|
|
|
15779
15930
|
// ../core/src/vault.ts
|
|
15780
|
-
import { bytesToHex as bytesToHex10, encodeAbiParameters as
|
|
15931
|
+
import { bytesToHex as bytesToHex10, encodeAbiParameters as encodeAbiParameters6, encodeFunctionData as encodeFunctionData7, getAddress as getAddress16, isAddress as isAddress8, keccak256 as keccak25611, zeroAddress as zeroAddress9 } from "viem";
|
|
15781
15932
|
function spendGas(calls) {
|
|
15782
15933
|
return calls.reduce((gas, c) => gas + reservedSwapGas(c), VAULT_SPEND_GAS);
|
|
15783
15934
|
}
|
|
@@ -15822,9 +15973,9 @@ var init_vault = __esm({
|
|
|
15822
15973
|
if (kind === "private" !== (privateIndex !== null)) throw new Error("a private vault, and only a private vault, has an index");
|
|
15823
15974
|
if (kind === "token" && vaultToken === null) throw new Error("a token vault names its token");
|
|
15824
15975
|
if (vaultToken !== null && kind !== "token" && kind !== "creator") throw new Error("only a token vault or a creator vault names its token");
|
|
15825
|
-
if (vaultToken !== null &&
|
|
15976
|
+
if (vaultToken !== null && getAddress16(vaultToken) === config.deployment.token) throw new Error(`the vault in ${vaultToken} is the ${kind === "creator" ? "USDG creator vault, named without a token" : "buyer vault, not a token vault"}`);
|
|
15826
15977
|
this.kind = kind;
|
|
15827
|
-
this.token = vaultToken === null ? config.deployment.token :
|
|
15978
|
+
this.token = vaultToken === null ? config.deployment.token : getAddress16(vaultToken);
|
|
15828
15979
|
this.privateIndex = privateIndex;
|
|
15829
15980
|
this.#client = client;
|
|
15830
15981
|
this.#transport = transport;
|
|
@@ -15839,7 +15990,7 @@ var init_vault = __esm({
|
|
|
15839
15990
|
setInitCrank(crank) {
|
|
15840
15991
|
if (this.kind !== "seller") throw new Error(`the ${this.kind} vault is created without a crank`);
|
|
15841
15992
|
if (!isAddress8(crank, { strict: false })) throw new RangeError("a crank is an address");
|
|
15842
|
-
this.#initCrank =
|
|
15993
|
+
this.#initCrank = getAddress16(crank);
|
|
15843
15994
|
}
|
|
15844
15995
|
/** A vault in the deployment's token (USDG); else a token vault or a pair's creator vault, paid for by the buyer vault. */
|
|
15845
15996
|
#inUsdg() {
|
|
@@ -15879,10 +16030,10 @@ var init_vault = __esm({
|
|
|
15879
16030
|
return null;
|
|
15880
16031
|
}
|
|
15881
16032
|
const r = JSON.parse(text2);
|
|
15882
|
-
if (r.chainId !== this.#config.chainId || typeof r.token !== "string" ||
|
|
16033
|
+
if (r.chainId !== this.#config.chainId || typeof r.token !== "string" || getAddress16(r.token) !== this.token || typeof r.vault !== "string" || !isAddress8(r.vault, { strict: false })) {
|
|
15883
16034
|
throw new Error(`${this.#adoptedName()} is not a recovered vault of chain ${this.#config.chainId} in ${this.token}`);
|
|
15884
16035
|
}
|
|
15885
|
-
this.#adopted =
|
|
16036
|
+
this.#adopted = getAddress16(r.vault);
|
|
15886
16037
|
return this.#adopted;
|
|
15887
16038
|
}
|
|
15888
16039
|
async vaultAddress() {
|
|
@@ -16134,7 +16285,7 @@ var init_vault = __esm({
|
|
|
16134
16285
|
const s2 = decodeVaultSpendMessage(message);
|
|
16135
16286
|
const { devBuy, launchHash: hash } = decodeDevBuyParams(s2.params);
|
|
16136
16287
|
const lp = this.#config.deployment.launchpad;
|
|
16137
|
-
if (lp === void 0 ||
|
|
16288
|
+
if (lp === void 0 || getAddress16(devBuy) !== lp.devBuy) throw new Error(`the vault signed a DevBuy for ${devBuy}, not this deployment's OstraDevBuy`);
|
|
16138
16289
|
const l = await this.#signedLaunch(vault, v.nonce, hash);
|
|
16139
16290
|
const call = { to: lp.devBuy, data: launchFromVaultData(l.launch, l.dev, { nextKeyRoot: s2.nextKeyRoot, signature }) };
|
|
16140
16291
|
const txHash2 = await sender.send([call], { reservation, value: LAUNCHPAD.FEE_WEI });
|
|
@@ -16237,7 +16388,7 @@ the signed ${op.what} is kept; the next call on this vault sends it again before
|
|
|
16237
16388
|
const amount = parseTokenAmount(amountText);
|
|
16238
16389
|
if (amount === 0n) throw new RangeError("amount must be greater than zero");
|
|
16239
16390
|
if (!isAddress8(destinationText, { strict: false })) throw new RangeError(`${destinationText} is not an address`);
|
|
16240
|
-
const destination =
|
|
16391
|
+
const destination = getAddress16(destinationText);
|
|
16241
16392
|
if (destination === zeroAddress9) throw new RangeError("the destination must not be the zero address");
|
|
16242
16393
|
await this.#checkToken();
|
|
16243
16394
|
const vault = await this.vaultAddress();
|
|
@@ -16288,7 +16439,7 @@ the signed withdrawal is kept; the next withdraw or open_channel call sends it a
|
|
|
16288
16439
|
if (this.kind === "seller") throw new Error("channels are not opened from the seller vault");
|
|
16289
16440
|
await this.#checkToken();
|
|
16290
16441
|
const vault = await this.vaultAddress();
|
|
16291
|
-
if (
|
|
16442
|
+
if (getAddress16(open3.receiverAuthorizer) === vault || getAddress16(open3.receiver) === vault) throw new Error("the channel would pay this agent's own vault");
|
|
16292
16443
|
if (await this.#read(vault) === null) throw new Error(this.#missing());
|
|
16293
16444
|
await this.requireEth(VAULT_SPEND_GAS, "send the vault operation");
|
|
16294
16445
|
return this.#paidSpend(this.#sender, async (sender, reservation) => {
|
|
@@ -16362,7 +16513,7 @@ the signed channel open is kept; the next open_channel or withdraw call sends it
|
|
|
16362
16513
|
setCrankKey(crankText, via) {
|
|
16363
16514
|
return this.#serial(async () => {
|
|
16364
16515
|
if (!isAddress8(crankText, { strict: false })) throw new RangeError("a crank is an address");
|
|
16365
|
-
const crank =
|
|
16516
|
+
const crank = getAddress16(crankText);
|
|
16366
16517
|
const target = crank === zeroAddress9 ? null : crank;
|
|
16367
16518
|
const vault = await this.vaultAddress();
|
|
16368
16519
|
if (await this.#read(vault) === null) throw new Error(this.#missing());
|
|
@@ -16450,7 +16601,7 @@ the signed operation is kept; the next call on this vault sends it again before
|
|
|
16450
16601
|
/** Adds (enabled) or removes a guardian of this vault: another Ostra vault keeps the recovery post-quantum. */
|
|
16451
16602
|
async setGuardian(guardianText, enabled, via) {
|
|
16452
16603
|
if (!isAddress8(guardianText, { strict: false })) throw new RangeError(`${guardianText} is not an address`);
|
|
16453
|
-
const guardian =
|
|
16604
|
+
const guardian = getAddress16(guardianText);
|
|
16454
16605
|
if (guardian === zeroAddress9) throw new RangeError("a guardian is not the zero address");
|
|
16455
16606
|
return this.#recoverySpend(
|
|
16456
16607
|
(v) => signVaultSetGuardian(this.#keychain, v, { chainId: this.#config.chainId, guardian, enabled }),
|
|
@@ -16496,7 +16647,7 @@ the signed operation is kept; the next call on this vault sends it again before
|
|
|
16496
16647
|
/** As a guardian (this vault), supports moving `vaultText` to `newKeyRootText` (the key root its owner's new device gave). */
|
|
16497
16648
|
async supportRecovery(vaultText, newKeyRootText, via) {
|
|
16498
16649
|
if (!isAddress8(vaultText, { strict: false })) throw new RangeError(`${vaultText} is not an address`);
|
|
16499
|
-
const target =
|
|
16650
|
+
const target = getAddress16(vaultText);
|
|
16500
16651
|
if (!/^0x[0-9a-fA-F]{64}$/.test(newKeyRootText) || /^0x0{64}$/.test(newKeyRootText)) throw new RangeError("the new key root is 32 bytes of 0x hex, not zero");
|
|
16501
16652
|
const newKeyRoot = newKeyRootText.toLowerCase();
|
|
16502
16653
|
return this.#recoverySpend(
|
|
@@ -16509,7 +16660,7 @@ the signed operation is kept; the next call on this vault sends it again before
|
|
|
16509
16660
|
if (!await read("isGuardian", [vault])) throw new Error(`this vault ${vault} is not a guardian of ${target}`);
|
|
16510
16661
|
const r = await readRecovery(this.#client, target);
|
|
16511
16662
|
if (r.threshold === 0) throw new Error(`${target} has recovery turned off`);
|
|
16512
|
-
const proposal =
|
|
16663
|
+
const proposal = keccak25611(encodeAbiParameters6([{ type: "uint32" }, { type: "bytes32" }], [r.round, newKeyRoot]));
|
|
16513
16664
|
return await read("supportedBy", [proposal, vault]);
|
|
16514
16665
|
},
|
|
16515
16666
|
via
|
|
@@ -16525,7 +16676,7 @@ the signed operation is kept; the next call on this vault sends it again before
|
|
|
16525
16676
|
return this.#serial(async () => {
|
|
16526
16677
|
if (this.kind === "private") throw new Error("a private vault is recovered with the seed that unshielded it");
|
|
16527
16678
|
if (!isAddress8(vaultText, { strict: false })) throw new RangeError(`${vaultText} is not an address`);
|
|
16528
|
-
const vault =
|
|
16679
|
+
const vault = getAddress16(vaultText);
|
|
16529
16680
|
const v = await readVault(this.#client, this.#config.deployment, vault);
|
|
16530
16681
|
if (v === null || v.token !== this.token) throw new Error(`${vault} is not an Ostra vault in ${this.token}`);
|
|
16531
16682
|
const adopted = await this.#adoptedVault();
|
|
@@ -16583,7 +16734,7 @@ the signed operation is kept; the next call on this vault sends it again before
|
|
|
16583
16734
|
});
|
|
16584
16735
|
|
|
16585
16736
|
// ../core/src/launchpad.ts
|
|
16586
|
-
import { bytesToHex as bytesToHex11, decodeEventLog as decodeEventLog3, encodeFunctionData as encodeFunctionData8, getAddress as
|
|
16737
|
+
import { bytesToHex as bytesToHex11, decodeEventLog as decodeEventLog3, encodeFunctionData as encodeFunctionData8, getAddress as getAddress17, isAddress as isAddress9, parseAbiItem as parseAbiItem2, zeroAddress as zeroAddress10 } from "viem";
|
|
16587
16738
|
async function readIpfsJson(uri2) {
|
|
16588
16739
|
if (uri2 === null || !uri2.startsWith("ipfs://")) return null;
|
|
16589
16740
|
const path = uri2.slice("ipfs://".length).replace(/^ipfs\//, "");
|
|
@@ -16620,7 +16771,7 @@ function nowIso(seconds) {
|
|
|
16620
16771
|
}
|
|
16621
16772
|
function address2(text2, what) {
|
|
16622
16773
|
if (!isAddress9(text2, { strict: false })) throw new RangeError(`${what} ${text2} is not an address`);
|
|
16623
|
-
return
|
|
16774
|
+
return getAddress17(text2);
|
|
16624
16775
|
}
|
|
16625
16776
|
function slippage(bps) {
|
|
16626
16777
|
const s = bps ?? QUOTE_DEFAULT_SLIPPAGE_BPS;
|
|
@@ -16723,8 +16874,8 @@ var init_launchpad = __esm({
|
|
|
16723
16874
|
*/
|
|
16724
16875
|
async #notStranded(to, paid, what) {
|
|
16725
16876
|
const v = await readVault(this.#client, this.#config.deployment, to);
|
|
16726
|
-
if (v !== null && v.token !==
|
|
16727
|
-
throw new Error(`${to} is an Ostra vault in ${v.token}: a vault only moves its own token, so ${what} in ${
|
|
16877
|
+
if (v !== null && v.token !== getAddress17(paid)) {
|
|
16878
|
+
throw new Error(`${to} is an Ostra vault in ${v.token}: a vault only moves its own token, so ${what} in ${getAddress17(paid)} would be stuck there for good; nothing was signed`);
|
|
16728
16879
|
}
|
|
16729
16880
|
}
|
|
16730
16881
|
/** The token a pair's vaults hold: the pair's own; WETH for ETH. */
|
|
@@ -16816,9 +16967,9 @@ var init_launchpad = __esm({
|
|
|
16816
16967
|
const pool = await this.#pool(tokenText);
|
|
16817
16968
|
const s = await this.tokenVault(pool.token).state();
|
|
16818
16969
|
let dividends = null;
|
|
16819
|
-
if (
|
|
16970
|
+
if (getAddress17(pool.config.dividendToken) !== zeroAddress10) {
|
|
16820
16971
|
const owed = await this.#client.readContract({ address: pool.token, abi: ostraTokenAbi, functionName: "dividendOf", args: [s.vault] });
|
|
16821
|
-
const decimals =
|
|
16972
|
+
const decimals = getAddress17(pool.config.dividendToken) === this.#usdg() ? TOKEN_DECIMALS : await tokenDecimals(this.#client, getAddress17(pool.config.dividendToken));
|
|
16822
16973
|
dividends = formatUnitsAmount(owed, decimals);
|
|
16823
16974
|
}
|
|
16824
16975
|
return { token: pool.token, vault: s.vault, exists: s.exists, balance: formatUnitsAmount(s.balance, 18), dividends, pendingOperation: s.pendingAction };
|
|
@@ -16846,7 +16997,7 @@ var init_launchpad = __esm({
|
|
|
16846
16997
|
const pair3 = findLaunchPair(quote);
|
|
16847
16998
|
if (pair3 === null) throw new Error(`the pool of ${pool.token} trades against ${quote}, not a pair Ostra offers (USDG, ETH, OSTRA or a listed stock token); nothing was signed`);
|
|
16848
16999
|
const referrer = a.referrer === void 0 ? void 0 : address2(a.referrer, "referrer");
|
|
16849
|
-
const quoteIs0 =
|
|
17000
|
+
const quoteIs0 = getAddress17(pool.key.currency0) === quote;
|
|
16850
17001
|
const buying = a.side === "buy";
|
|
16851
17002
|
const quoteVault = this.tokenVault(quote);
|
|
16852
17003
|
const from = buying ? quoteVault : this.tokenVault(pool.token);
|
|
@@ -16877,7 +17028,7 @@ var init_launchpad = __esm({
|
|
|
16877
17028
|
async #swapOutcome(txHash, vault) {
|
|
16878
17029
|
const receipt = await this.#client.getTransactionReceipt({ hash: txHash });
|
|
16879
17030
|
for (const log2 of receipt.logs) {
|
|
16880
|
-
if (
|
|
17031
|
+
if (getAddress17(log2.address) !== vault) continue;
|
|
16881
17032
|
try {
|
|
16882
17033
|
const e = decodeEventLog3({ abi: ostraVaultAbi, topics: log2.topics, data: log2.data });
|
|
16883
17034
|
if (e.eventName === "Swapped") {
|
|
@@ -16969,7 +17120,7 @@ var init_launchpad = __esm({
|
|
|
16969
17120
|
/** Claims the dividends the agent's token vault for `token` earned, into the agent's vault of the dividend token. */
|
|
16970
17121
|
async claimDividends(tokenText) {
|
|
16971
17122
|
const pool = await this.#pool(tokenText);
|
|
16972
|
-
const dividendToken =
|
|
17123
|
+
const dividendToken = getAddress17(pool.config.dividendToken);
|
|
16973
17124
|
if (dividendToken === zeroAddress10) throw new Error(`the pool of ${pool.token} pays no dividends`);
|
|
16974
17125
|
const v = this.tokenVault(pool.token);
|
|
16975
17126
|
const s = await v.state();
|
|
@@ -17077,7 +17228,7 @@ var init_launchpad = __esm({
|
|
|
17077
17228
|
creatorVault,
|
|
17078
17229
|
startTick
|
|
17079
17230
|
});
|
|
17080
|
-
const token =
|
|
17231
|
+
const token = getAddress17(await this.#client.readContract({ address: lp.devBuy, abi: ostraDevBuyAbi, functionName: "tokenAddressFromVault", args: [p] }));
|
|
17081
17232
|
const tokenVault = await this.tokenVault(token).vaultAddress();
|
|
17082
17233
|
let dev = NO_DEV_BUY;
|
|
17083
17234
|
if (input.devBuy !== void 0) {
|
|
@@ -17085,7 +17236,7 @@ var init_launchpad = __esm({
|
|
|
17085
17236
|
if (quoteIn === 0n) throw new RangeError("the dev buy amount must be greater than zero (leave devBuy out for none)");
|
|
17086
17237
|
const cliff = Math.round((input.devBuy.cliffDays ?? DEV_BUY.MIN_CLIFF / DAY) * DAY);
|
|
17087
17238
|
const duration = Math.round((input.devBuy.vestingDays ?? 0) * DAY);
|
|
17088
|
-
const dividendToken =
|
|
17239
|
+
const dividendToken = getAddress17(p.dividendToken);
|
|
17089
17240
|
dev = {
|
|
17090
17241
|
quoteIn,
|
|
17091
17242
|
beneficiary: tokenVault,
|
|
@@ -17123,14 +17274,14 @@ var init_launchpad = __esm({
|
|
|
17123
17274
|
let bought = null;
|
|
17124
17275
|
for (const log2 of receipt.logs) {
|
|
17125
17276
|
try {
|
|
17126
|
-
if (
|
|
17277
|
+
if (getAddress17(log2.address) === lp.launchpad) {
|
|
17127
17278
|
const e = decodeEventLog3({ abi: ostraLaunchpadAbi, topics: log2.topics, data: log2.data });
|
|
17128
17279
|
if (e.eventName === "Launched") poolId2 = e.args.poolId;
|
|
17129
|
-
} else if (
|
|
17280
|
+
} else if (getAddress17(log2.address) === lp.devBuy) {
|
|
17130
17281
|
const e = decodeEventLog3({ abi: ostraDevBuyAbi, topics: log2.topics, data: log2.data });
|
|
17131
17282
|
if (e.eventName === "DevBought") {
|
|
17132
17283
|
const g = e.args;
|
|
17133
|
-
bought = { ...g, vesting:
|
|
17284
|
+
bought = { ...g, vesting: getAddress17(g.vesting) };
|
|
17134
17285
|
}
|
|
17135
17286
|
}
|
|
17136
17287
|
} catch {
|
|
@@ -17167,7 +17318,7 @@ var init_launchpad = __esm({
|
|
|
17167
17318
|
if (pair3 === null) throw new Error(`the pool of ${pool.token} trades against ${this.#quoteOf(pool)}, not a pair Ostra offers; no creator vault of this agent owns it`);
|
|
17168
17319
|
const { vault: creator, sender } = await this.pairCreator(pair3.symbol);
|
|
17169
17320
|
const creatorVault = await creator.vaultAddress();
|
|
17170
|
-
if (
|
|
17321
|
+
if (getAddress17(pool.config.creatorVault) !== creatorVault) throw new Error(`the pool of ${pool.token} belongs to the creator vault ${pool.config.creatorVault}, not this agent's ${pair3.symbol} creator vault ${creatorVault}`);
|
|
17171
17322
|
return { pool, pair: pair3, creator, sender };
|
|
17172
17323
|
}
|
|
17173
17324
|
/**
|
|
@@ -17220,7 +17371,7 @@ var init_launchpad = __esm({
|
|
|
17220
17371
|
if (amountIn === 0n) throw new RangeError("amount must be greater than zero");
|
|
17221
17372
|
const s = await creator.state();
|
|
17222
17373
|
if (s.balance < amountIn) throw new Error(`the ${pair3.symbol} creator vault holds ${formatUnitsAmount(s.balance, pair3.decimals)}, less than ${a.amount}; fund it with fund_creator_vault`);
|
|
17223
|
-
const quoteIs0 =
|
|
17374
|
+
const quoteIs0 = getAddress17(pool.key.currency0) === pair3.address;
|
|
17224
17375
|
const q = await quoteVaultSwap(this.#client, this.#config.deployment, {
|
|
17225
17376
|
vault: s.vault,
|
|
17226
17377
|
relayer: await sender.payer(),
|
|
@@ -17306,7 +17457,7 @@ var init_launchpad = __esm({
|
|
|
17306
17457
|
} else {
|
|
17307
17458
|
const text2 = await this.#folder.read(this.#airdropName(pool.id, r.number));
|
|
17308
17459
|
if (text2 === void 0) throw new Error(`no tree of round ${r.number} is kept here; give the amount and proof`);
|
|
17309
|
-
const claim = JSON.parse(text2).claims.find((c) =>
|
|
17460
|
+
const claim = JSON.parse(text2).claims.find((c) => getAddress17(c.account) === account);
|
|
17310
17461
|
if (claim === void 0) throw new Error(`${account} is not in round ${r.number}`);
|
|
17311
17462
|
amount = BigInt(claim.amount);
|
|
17312
17463
|
proof = claim.proof;
|
|
@@ -17341,7 +17492,7 @@ var init_launchpad = __esm({
|
|
|
17341
17492
|
const text2 = await this.#folder.read(this.#launchName(token));
|
|
17342
17493
|
const v = text2 === void 0 ? null : JSON.parse(text2).vesting ?? null;
|
|
17343
17494
|
if (v === null) throw new Error(`this agent's records hold no dev buy vesting of ${token}; give its address`);
|
|
17344
|
-
vesting =
|
|
17495
|
+
vesting = getAddress17(v);
|
|
17345
17496
|
}
|
|
17346
17497
|
const id = await this.#client.readContract({ address: lp.devBuy, abi: ostraDevBuyAbi, functionName: "vestingPool", args: [vesting] });
|
|
17347
17498
|
if (BigInt(id) === 0n) throw new Error(`${vesting} is not an Ostra dev buy's vesting`);
|
|
@@ -17352,8 +17503,8 @@ var init_launchpad = __esm({
|
|
|
17352
17503
|
const vesting = await this.#vesting(a.token, a.vesting);
|
|
17353
17504
|
const read = (functionName) => this.#client.readContract({ address: vesting, abi: ostraVestingAbi, functionName });
|
|
17354
17505
|
const [terms, schedule, releasable] = await Promise.all([read("terms"), read("schedule"), read("releasable")]);
|
|
17355
|
-
const held = await tokenBalance(this.#client,
|
|
17356
|
-
return { vesting, beneficiary:
|
|
17506
|
+
const held = await tokenBalance(this.#client, getAddress17(terms.token), vesting);
|
|
17507
|
+
return { vesting, beneficiary: getAddress17(terms.beneficiary), cliffEnd: nowIso(schedule[0]), end: nowIso(schedule[1]), held: formatUnitsAmount(held, 18), releasable: formatUnitsAmount(releasable, 18) };
|
|
17357
17508
|
}
|
|
17358
17509
|
/** Releases what the vesting has vested to its beneficiary (this agent's token vault). */
|
|
17359
17510
|
async vestingRelease(a) {
|
|
@@ -17390,7 +17541,7 @@ var init_launchpad = __esm({
|
|
|
17390
17541
|
await this.#folder.ensure();
|
|
17391
17542
|
const text2 = await this.#folder.read("token-index.json");
|
|
17392
17543
|
let index = text2 === void 0 ? { version: 1, launchpad: lp.launchpad, scannedTo: (BigInt(this.#config.deployment.fromBlock) - 1n).toString(), launches: [] } : JSON.parse(text2);
|
|
17393
|
-
if (
|
|
17544
|
+
if (getAddress17(index.launchpad) !== getAddress17(lp.launchpad)) index = { version: 1, launchpad: lp.launchpad, scannedTo: (BigInt(this.#config.deployment.fromBlock) - 1n).toString(), launches: [] };
|
|
17394
17545
|
const latest = await this.#client.getBlockNumber();
|
|
17395
17546
|
let from = BigInt(index.scannedTo) + 1n;
|
|
17396
17547
|
if (from > latest) return index;
|
|
@@ -17399,7 +17550,7 @@ var init_launchpad = __esm({
|
|
|
17399
17550
|
const logs = await this.#client.getLogs({ address: lp.launchpad, event: launchedEvent, fromBlock: from, toBlock: to });
|
|
17400
17551
|
for (const l of logs) {
|
|
17401
17552
|
if (l.args.token === void 0 || l.args.poolId === void 0 || l.args.creatorVault === void 0 || l.args.quote === void 0 || l.transactionHash === null || l.blockNumber === null) continue;
|
|
17402
|
-
index.launches.push({ token:
|
|
17553
|
+
index.launches.push({ token: getAddress17(l.args.token), poolId: l.args.poolId, creatorVault: getAddress17(l.args.creatorVault), quote: getAddress17(l.args.quote), block: l.blockNumber.toString(), txHash: l.transactionHash });
|
|
17403
17554
|
}
|
|
17404
17555
|
index.scannedTo = to.toString();
|
|
17405
17556
|
}
|
|
@@ -17499,7 +17650,7 @@ var init_launchpad = __esm({
|
|
|
17499
17650
|
const receipt = await this.#client.getTransactionReceipt({ hash: r.txHash });
|
|
17500
17651
|
let agentId;
|
|
17501
17652
|
for (const log2 of receipt.logs) {
|
|
17502
|
-
if (
|
|
17653
|
+
if (getAddress17(log2.address) !== vault) continue;
|
|
17503
17654
|
try {
|
|
17504
17655
|
const e = decodeEventLog3({ abi: ostraVaultAbi, data: log2.data, topics: log2.topics });
|
|
17505
17656
|
if (e.eventName === "AgentRegistered") agentId = e.args.agentId.toString();
|
|
@@ -17588,17 +17739,17 @@ var init_launchpad = __esm({
|
|
|
17588
17739
|
});
|
|
17589
17740
|
|
|
17590
17741
|
// ../core/src/pay.ts
|
|
17591
|
-
import { getAddress as
|
|
17742
|
+
import { getAddress as getAddress18, isAddress as isAddress10 } from "viem";
|
|
17592
17743
|
import { x402Client as x402Client2, x402HTTPClient as x402HTTPClient2 } from "@x402/core/client";
|
|
17593
17744
|
import { toClientEvmSigner as toClientEvmSigner2 } from "@x402/evm";
|
|
17594
17745
|
import { BatchSettlementEvmScheme as BatchSettlementEvmScheme2 } from "@x402/evm/batch-settlement/client";
|
|
17595
17746
|
function offerProblem(r, network, token) {
|
|
17596
17747
|
if (r.scheme !== "batch-settlement") return `${r.scheme} (this agent pays batch-settlement)`;
|
|
17597
17748
|
if (r.network !== network) return `on ${r.network} (this agent pays on ${network})`;
|
|
17598
|
-
if (!isAddress10(r.asset, { strict: false }) ||
|
|
17749
|
+
if (!isAddress10(r.asset, { strict: false }) || getAddress18(r.asset) !== token) return `in ${r.asset} (this agent pays in ${token})`;
|
|
17599
17750
|
return null;
|
|
17600
17751
|
}
|
|
17601
|
-
var PAY_CHANNEL_DEPOSIT, PAY_MAX_BODY_CHARS,
|
|
17752
|
+
var PAY_CHANNEL_DEPOSIT, PAY_MAX_BODY_CHARS, REQUEST_TIMEOUT_MS3, MIN_LIFE_LEFT_SECONDS, now2, PayService;
|
|
17602
17753
|
var init_pay = __esm({
|
|
17603
17754
|
"../core/src/pay.ts"() {
|
|
17604
17755
|
"use strict";
|
|
@@ -17609,7 +17760,7 @@ var init_pay = __esm({
|
|
|
17609
17760
|
init_channels();
|
|
17610
17761
|
PAY_CHANNEL_DEPOSIT = 1000000n;
|
|
17611
17762
|
PAY_MAX_BODY_CHARS = 65536;
|
|
17612
|
-
|
|
17763
|
+
REQUEST_TIMEOUT_MS3 = 12e4;
|
|
17613
17764
|
MIN_LIFE_LEFT_SECONDS = 300;
|
|
17614
17765
|
now2 = () => Math.floor(Date.now() / 1e3);
|
|
17615
17766
|
PayService = class {
|
|
@@ -17635,23 +17786,23 @@ var init_pay = __esm({
|
|
|
17635
17786
|
method: input.method ?? "GET",
|
|
17636
17787
|
headers: { ...input.headers ?? {}, ...headers },
|
|
17637
17788
|
...input.body === void 0 ? {} : { body: input.body },
|
|
17638
|
-
signal: AbortSignal.timeout(
|
|
17789
|
+
signal: AbortSignal.timeout(input.timeoutMs ?? REQUEST_TIMEOUT_MS3),
|
|
17639
17790
|
redirect: "manual"
|
|
17640
17791
|
});
|
|
17641
17792
|
} catch (err) {
|
|
17642
17793
|
throw new Error(`${input.url} cannot be reached: ${err.message}`);
|
|
17643
17794
|
}
|
|
17644
17795
|
}
|
|
17645
|
-
async #answer(res, paid, record, note) {
|
|
17796
|
+
async #answer(res, paid, record, note, maxBodyChars = PAY_MAX_BODY_CHARS) {
|
|
17646
17797
|
const text2 = await res.text();
|
|
17647
|
-
const truncated = text2.length >
|
|
17798
|
+
const truncated = text2.length > maxBodyChars;
|
|
17648
17799
|
return {
|
|
17649
17800
|
status: res.status,
|
|
17650
17801
|
paid: paid === null ? null : formatTokenAmount(paid),
|
|
17651
17802
|
channel: record === null ? null : record.channel,
|
|
17652
17803
|
channelLeft: record === null ? null : formatTokenAmount(payCapacity(record)),
|
|
17653
17804
|
contentType: res.headers.get("content-type"),
|
|
17654
|
-
body: truncated ? text2.slice(0,
|
|
17805
|
+
body: truncated ? text2.slice(0, maxBodyChars) : text2,
|
|
17655
17806
|
truncated,
|
|
17656
17807
|
...note === void 0 ? {} : { note }
|
|
17657
17808
|
};
|
|
@@ -17660,7 +17811,7 @@ var init_pay = __esm({
|
|
|
17660
17811
|
async #channelFor(payee, receiver, withdrawDelay, price) {
|
|
17661
17812
|
for (const r of await this.#channels.payRecords()) {
|
|
17662
17813
|
if (r.pay === void 0 || r.closeRequested) continue;
|
|
17663
|
-
if (
|
|
17814
|
+
if (getAddress18(r.payee) !== payee || getAddress18(r.config.receiver) !== receiver || r.gracePeriod !== withdrawDelay) continue;
|
|
17664
17815
|
if (r.pay.expiresAt < now2() + MIN_LIFE_LEFT_SECONDS || payCapacity(r) < price) continue;
|
|
17665
17816
|
const ch = await readChannel(this.#client, this.#config.deployment.batchSettlement, r.channel);
|
|
17666
17817
|
if (ch.pendingWithdrawal !== null || ch.balance < BigInt(r.pay.cumulative) + price) continue;
|
|
@@ -17671,10 +17822,10 @@ var init_pay = __esm({
|
|
|
17671
17822
|
/** The stock x402 client paying from channel record `r` (the vault as payer, the channel's voucher key signing, never depositing). */
|
|
17672
17823
|
#x402(r) {
|
|
17673
17824
|
const voucherKey = this.#channels.voucherSigner(r);
|
|
17674
|
-
if (voucherKey.address !==
|
|
17825
|
+
if (voucherKey.address !== getAddress18(r.config.payerAuthorizer)) throw new Error(`the voucher key of channel ${r.channel} is not derived from this machine's master seed`);
|
|
17675
17826
|
const client = this.#client;
|
|
17676
17827
|
const payer = {
|
|
17677
|
-
address:
|
|
17828
|
+
address: getAddress18(r.config.payer),
|
|
17678
17829
|
signTypedData: () => Promise.reject(new Error("a vault never signs typed data")),
|
|
17679
17830
|
readContract: (args) => client.readContract(args)
|
|
17680
17831
|
};
|
|
@@ -17719,7 +17870,7 @@ var init_pay = __esm({
|
|
|
17719
17870
|
if (url.protocol !== "https:" && url.protocol !== "http:") throw new RangeError("pay sends http(s) requests only");
|
|
17720
17871
|
const maxPrice = parseTokenAmount(input.maxPrice);
|
|
17721
17872
|
const first = await this.#fetch(input);
|
|
17722
|
-
if (first.status !== 402) return this.#answer(first, null, null);
|
|
17873
|
+
if (first.status !== 402) return this.#answer(first, null, null, void 0, input.maxBodyChars);
|
|
17723
17874
|
let firstBody = null;
|
|
17724
17875
|
try {
|
|
17725
17876
|
firstBody = JSON.parse(await first.clone().text());
|
|
@@ -17743,13 +17894,13 @@ var init_pay = __esm({
|
|
|
17743
17894
|
if (price > maxPrice) throw new Error(`${input.url} asks ${formatTokenAmount(price)}, more than maxPrice ${input.maxPrice}; nothing was paid`);
|
|
17744
17895
|
const extra = offer.extra ?? {};
|
|
17745
17896
|
if (typeof extra.receiverAuthorizer !== "string" || !isAddress10(extra.receiverAuthorizer, { strict: false })) throw new Error("the offer names no receiverAuthorizer; nothing was paid");
|
|
17746
|
-
const payee =
|
|
17897
|
+
const payee = getAddress18(extra.receiverAuthorizer);
|
|
17747
17898
|
const withdrawDelay = extra.withdrawDelay;
|
|
17748
17899
|
if (typeof withdrawDelay !== "number" || !Number.isInteger(withdrawDelay) || withdrawDelay < 900 || withdrawDelay > BATCH_MAX_WITHDRAW_DELAY_SECONDS) {
|
|
17749
17900
|
throw new Error(`the offer's withdrawDelay ${String(withdrawDelay)} is not 900..${BATCH_MAX_WITHDRAW_DELAY_SECONDS} s; nothing was paid`);
|
|
17750
17901
|
}
|
|
17751
17902
|
if (!isAddress10(offer.payTo, { strict: false })) throw new Error("the offer's payTo is not an address; nothing was paid");
|
|
17752
|
-
const receiver =
|
|
17903
|
+
const receiver = getAddress18(offer.payTo);
|
|
17753
17904
|
const payeeVault = await readVault(this.#client, this.#config.deployment, payee);
|
|
17754
17905
|
if (payeeVault === null || payeeVault.token !== token) throw new Error(`the seller's receiverAuthorizer ${payee} is not an Ostra vault in ${token}: this agent pays Ostra sellers from its vault; nothing was paid`);
|
|
17755
17906
|
if (payee === await this.#vault.vaultAddress()) throw new Error("the seller is this agent's own vault");
|
|
@@ -17805,12 +17956,12 @@ var init_pay = __esm({
|
|
|
17805
17956
|
break;
|
|
17806
17957
|
}
|
|
17807
17958
|
if (answer.status === 402) {
|
|
17808
|
-
return this.#answer(answer, null, r, "the seller did not take the voucher; what the voucher signed stays recorded against the channel");
|
|
17959
|
+
return this.#answer(answer, null, r, "the seller did not take the voucher; what the voucher signed stays recorded against the channel", input.maxBodyChars);
|
|
17809
17960
|
}
|
|
17810
17961
|
const done = await this.#channels.updatePayRecord(r.salt, (rec) => {
|
|
17811
17962
|
rec.pay.payments.push({ url: input.url, amount: paid.toString(), transaction: answer.headers.get("payment-response") ?? "", at: now2() });
|
|
17812
17963
|
});
|
|
17813
|
-
return this.#answer(answer, paid, done, opened ? `a channel to the seller was opened with a deposit of ${formatTokenAmount(BigInt(done.deposit))}; later payments to the seller use it` : void 0);
|
|
17964
|
+
return this.#answer(answer, paid, done, opened ? `a channel to the seller was opened with a deposit of ${formatTokenAmount(BigInt(done.deposit))}; later payments to the seller use it` : void 0, input.maxBodyChars);
|
|
17814
17965
|
});
|
|
17815
17966
|
}
|
|
17816
17967
|
};
|
|
@@ -20686,7 +20837,7 @@ var init_abi2 = __esm({
|
|
|
20686
20837
|
});
|
|
20687
20838
|
|
|
20688
20839
|
// ../../ostra-swap/sdk/src/constants.ts
|
|
20689
|
-
var LOG_WINDOW_BLOCKS2, USDG2, WETH2, HUBS, ETH, UNISWAP_V3_FACTORY, UNISWAP_V3_QUOTER_V2, V3_FEE_TIERS, UNISWAP_V4_POOL_MANAGER2, UNISWAP_V4_QUOTER, MULTICALL32, OSTRA_HOOK,
|
|
20840
|
+
var LOG_WINDOW_BLOCKS2, USDG2, WETH2, HUBS, ETH, UNISWAP_V3_FACTORY, UNISWAP_V3_QUOTER_V2, V3_FEE_TIERS, UNISWAP_V4_POOL_MANAGER2, UNISWAP_V4_QUOTER, MULTICALL32, OSTRA_HOOK, PONS_HOOK2, ROUTABLE_HOOKS, FEE_TIERS, COMMAND, V4_ACTION, CONTRACT_BALANCE, MSG_SENDER, ADDRESS_THIS, OPEN_DELTA, QUOTE_GAS_LIMIT, QUOTES_PER_CALL, QUOTE_GAS_LIMIT_RETRY, QUOTES_PER_RETRY_CALL, QUOTE_BATCH_OVERHEAD_GAS, V3_MIN_SQRT_PRICE_LIMIT, V3_MAX_SQRT_PRICE_LIMIT, DEFAULT_SLIPPAGE_BPS, MAX_SLIPPAGE_BPS, DEFAULT_ORDER_TTL_SECONDS;
|
|
20690
20841
|
var init_constants2 = __esm({
|
|
20691
20842
|
"../../ostra-swap/sdk/src/constants.ts"() {
|
|
20692
20843
|
"use strict";
|
|
@@ -20703,8 +20854,8 @@ var init_constants2 = __esm({
|
|
|
20703
20854
|
UNISWAP_V4_QUOTER = "0x8Dc178eFB8111BB0973Dd9d722ebeFF267c98F94";
|
|
20704
20855
|
MULTICALL32 = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
20705
20856
|
OSTRA_HOOK = "0x63A784afb8905452aDceC471a45E555F5caE68cC";
|
|
20706
|
-
|
|
20707
|
-
ROUTABLE_HOOKS = ["0x0000000000000000000000000000000000000000", OSTRA_HOOK,
|
|
20857
|
+
PONS_HOOK2 = "0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044";
|
|
20858
|
+
ROUTABLE_HOOKS = ["0x0000000000000000000000000000000000000000", OSTRA_HOOK, PONS_HOOK2];
|
|
20708
20859
|
FEE_TIERS = [
|
|
20709
20860
|
{ minLocked: 500000n * 10n ** 18n, bps: 0 },
|
|
20710
20861
|
{ minLocked: 250000n * 10n ** 18n, bps: 10 },
|
|
@@ -20827,13 +20978,13 @@ var init_uniswap = __esm({
|
|
|
20827
20978
|
});
|
|
20828
20979
|
|
|
20829
20980
|
// ../../ostra-swap/sdk/src/legs.ts
|
|
20830
|
-
import { concatHex, encodeAbiParameters as
|
|
20981
|
+
import { concatHex, encodeAbiParameters as encodeAbiParameters7, encodePacked as encodePacked4, getAddress as getAddress19, toHex as toHex3 } from "viem";
|
|
20831
20982
|
function legFor(pool, tokenIn, tokenOut, recipient = MSG_SENDER) {
|
|
20832
|
-
const inAddr =
|
|
20833
|
-
const outAddr =
|
|
20983
|
+
const inAddr = getAddress19(tokenIn);
|
|
20984
|
+
const outAddr = getAddress19(tokenOut);
|
|
20834
20985
|
if (pool.kind === "v3") {
|
|
20835
20986
|
const path = encodePacked4(["address", "uint24", "address"], [inAddr, pool.fee, outAddr]);
|
|
20836
|
-
const input =
|
|
20987
|
+
const input = encodeAbiParameters7(
|
|
20837
20988
|
[{ type: "address" }, { type: "uint256" }, { type: "uint256" }, { type: "bytes" }, { type: "bool" }, { type: "uint256[]" }],
|
|
20838
20989
|
[recipient, CONTRACT_BALANCE, 0n, path, false, []]
|
|
20839
20990
|
);
|
|
@@ -20843,20 +20994,20 @@ function legFor(pool, tokenIn, tokenOut, recipient = MSG_SENDER) {
|
|
|
20843
20994
|
const asCurrency = (t) => t === WETH2 && (k.currency0 === ETH || k.currency1 === ETH) ? ETH : t;
|
|
20844
20995
|
const currencyIn = asCurrency(inAddr);
|
|
20845
20996
|
const currencyOut = asCurrency(outAddr);
|
|
20846
|
-
const zeroForOne = currencyIn ===
|
|
20847
|
-
if (!zeroForOne && currencyIn !==
|
|
20848
|
-
if (currencyOut !==
|
|
20849
|
-
const settle =
|
|
20850
|
-
const swap =
|
|
20997
|
+
const zeroForOne = currencyIn === getAddress19(k.currency0);
|
|
20998
|
+
if (!zeroForOne && currencyIn !== getAddress19(k.currency1)) throw new Error(`${tokenIn} is not in the pool ${pool.id}`);
|
|
20999
|
+
if (currencyOut !== getAddress19(zeroForOne ? k.currency1 : k.currency0)) throw new Error(`${tokenOut} is not the other side of the pool ${pool.id}`);
|
|
21000
|
+
const settle = encodeAbiParameters7([{ type: "address" }, { type: "uint256" }, { type: "bool" }], [currencyIn, CONTRACT_BALANCE, false]);
|
|
21001
|
+
const swap = encodeAbiParameters7(
|
|
20851
21002
|
[exactInputSingleParam],
|
|
20852
21003
|
[{ poolKey: k, zeroForOne, amountIn: OPEN_DELTA, amountOutMinimum: 0n, minHopPriceX36: 0n, hookData: "0x" }]
|
|
20853
21004
|
);
|
|
20854
21005
|
if (recipient === ADDRESS_THIS && currencyOut === ETH) throw new Error("a leg kept in the Universal Router pays an ERC-20, not native ETH");
|
|
20855
|
-
const take =
|
|
21006
|
+
const take = encodeAbiParameters7([{ type: "address" }, { type: "address" }, { type: "uint256" }], [currencyOut, recipient, OPEN_DELTA]);
|
|
20856
21007
|
const actions = concatHex([byte(V4_ACTION.SETTLE), byte(V4_ACTION.SWAP_EXACT_IN_SINGLE), byte(V4_ACTION.TAKE)]);
|
|
20857
|
-
const v4Input =
|
|
21008
|
+
const v4Input = encodeAbiParameters7([{ type: "bytes" }, { type: "bytes[]" }], [actions, [settle, swap, take]]);
|
|
20858
21009
|
if (currencyIn === ETH) {
|
|
20859
|
-
const unwrap =
|
|
21010
|
+
const unwrap = encodeAbiParameters7([{ type: "address" }, { type: "uint256" }], [ADDRESS_THIS, 0n]);
|
|
20860
21011
|
return { commands: concatHex([byte(COMMAND.UNWRAP_WETH), byte(COMMAND.V4_SWAP)]), inputs: [unwrap, v4Input] };
|
|
20861
21012
|
}
|
|
20862
21013
|
return { commands: byte(COMMAND.V4_SWAP), inputs: [v4Input] };
|
|
@@ -20869,15 +21020,15 @@ var init_legs = __esm({
|
|
|
20869
21020
|
init_constants2();
|
|
20870
21021
|
init_uniswap();
|
|
20871
21022
|
NO_LEG = { commands: "0x", inputs: [] };
|
|
20872
|
-
byte = (n) =>
|
|
21023
|
+
byte = (n) => toHex3(n, { size: 1 });
|
|
20873
21024
|
}
|
|
20874
21025
|
});
|
|
20875
21026
|
|
|
20876
21027
|
// ../../ostra-swap/sdk/src/pools.ts
|
|
20877
|
-
import { encodeAbiParameters as
|
|
21028
|
+
import { encodeAbiParameters as encodeAbiParameters8, encodeFunctionData as encodeFunctionData9, decodeFunctionResult as decodeFunctionResult2, getAddress as getAddress20, hexToBigInt as hexToBigInt2, keccak256 as keccak25612, toHex as toHex4, zeroAddress as zeroAddress11 } from "viem";
|
|
20878
21029
|
function stateSlot(id, offset) {
|
|
20879
|
-
const base =
|
|
20880
|
-
return
|
|
21030
|
+
const base = hexToBigInt2(keccak25612(encodeAbiParameters8([{ type: "bytes32" }, { type: "uint256" }], [id, POOLS_SLOT3])));
|
|
21031
|
+
return toHex4(base + offset, { size: 32 });
|
|
20881
21032
|
}
|
|
20882
21033
|
async function initializeLogs(logsClient, c0, c1, from, to) {
|
|
20883
21034
|
try {
|
|
@@ -20889,7 +21040,7 @@ async function initializeLogs(logsClient, c0, c1, from, to) {
|
|
|
20889
21040
|
}
|
|
20890
21041
|
}
|
|
20891
21042
|
function hubCurrencies(hub) {
|
|
20892
|
-
return
|
|
21043
|
+
return getAddress20(hub) === WETH2 ? [WETH2, ETH] : [getAddress20(hub)];
|
|
20893
21044
|
}
|
|
20894
21045
|
async function aggregate(client, calls) {
|
|
20895
21046
|
if (calls.length === 0) return [];
|
|
@@ -20899,8 +21050,8 @@ async function aggregate(client, calls) {
|
|
|
20899
21050
|
return decodeFunctionResult2({ abi: multicall3Abi2, functionName: "aggregate3", data: ret });
|
|
20900
21051
|
}
|
|
20901
21052
|
async function hubPools(client, logsClient, index, token, hub) {
|
|
20902
|
-
const t =
|
|
20903
|
-
const h =
|
|
21053
|
+
const t = getAddress20(token);
|
|
21054
|
+
const h = getAddress20(hub);
|
|
20904
21055
|
if (t === h) return [];
|
|
20905
21056
|
const out = [];
|
|
20906
21057
|
const found = await aggregate(
|
|
@@ -20911,7 +21062,7 @@ async function hubPools(client, logsClient, index, token, hub) {
|
|
|
20911
21062
|
found.forEach((r, i) => {
|
|
20912
21063
|
if (!r.success) return;
|
|
20913
21064
|
const address6 = decodeFunctionResult2({ abi: v3FactoryAbi, functionName: "getPool", data: r.returnData });
|
|
20914
|
-
if (address6 !== zeroAddress11) v3.push({ address:
|
|
21065
|
+
if (address6 !== zeroAddress11) v3.push({ address: getAddress20(address6), fee: V3_FEE_TIERS[i] });
|
|
20915
21066
|
});
|
|
20916
21067
|
const v3Liquidity = await aggregate(client, v3.map((p) => ({ target: p.address, callData: encodeFunctionData9({ abi: v3PoolAbi, functionName: "liquidity" }) })));
|
|
20917
21068
|
v3.forEach((p, i) => {
|
|
@@ -20922,27 +21073,27 @@ async function hubPools(client, logsClient, index, token, hub) {
|
|
|
20922
21073
|
});
|
|
20923
21074
|
const records = [];
|
|
20924
21075
|
for (const side of hubCurrencies(h)) {
|
|
20925
|
-
for (const p of await index.v4PoolsOfPair(logsClient, t, side)) if (ROUTABLE_HOOKS.includes(
|
|
21076
|
+
for (const p of await index.v4PoolsOfPair(logsClient, t, side)) if (ROUTABLE_HOOKS.includes(getAddress20(p.key.hooks))) records.push(p);
|
|
20926
21077
|
}
|
|
20927
21078
|
if (records.length > 0) {
|
|
20928
|
-
const slots = records.map((p) => stateSlot(p.id,
|
|
21079
|
+
const slots = records.map((p) => stateSlot(p.id, LIQUIDITY_OFFSET2));
|
|
20929
21080
|
const values = await client.readContract({ address: UNISWAP_V4_POOL_MANAGER2, abi: poolManagerAbi, functionName: "extsload", args: [slots] });
|
|
20930
21081
|
records.forEach((p, i) => {
|
|
20931
21082
|
const v = values[i];
|
|
20932
|
-
if (v !== void 0 &&
|
|
21083
|
+
if (v !== void 0 && hexToBigInt2(v) % (1n << 128n) > 0n) out.push({ kind: "v4", id: p.id, key: p.key });
|
|
20933
21084
|
});
|
|
20934
21085
|
}
|
|
20935
21086
|
return out;
|
|
20936
21087
|
}
|
|
20937
|
-
var
|
|
21088
|
+
var POOLS_SLOT3, LIQUIDITY_OFFSET2, PoolIndex;
|
|
20938
21089
|
var init_pools2 = __esm({
|
|
20939
21090
|
"../../ostra-swap/sdk/src/pools.ts"() {
|
|
20940
21091
|
"use strict";
|
|
20941
21092
|
init_define_OSTRA_PACKAGED();
|
|
20942
21093
|
init_constants2();
|
|
20943
21094
|
init_uniswap();
|
|
20944
|
-
|
|
20945
|
-
|
|
21095
|
+
POOLS_SLOT3 = 6n;
|
|
21096
|
+
LIQUIDITY_OFFSET2 = 3n;
|
|
20946
21097
|
PoolIndex = class {
|
|
20947
21098
|
#data;
|
|
20948
21099
|
constructor(data) {
|
|
@@ -20958,7 +21109,7 @@ var init_pools2 = __esm({
|
|
|
20958
21109
|
* that serves LOG_WINDOW_BLOCKS per request).
|
|
20959
21110
|
*/
|
|
20960
21111
|
async v4PoolsOfPair(logsClient, a, b) {
|
|
20961
|
-
const [c0, c1] = BigInt(
|
|
21112
|
+
const [c0, c1] = BigInt(getAddress20(a)) < BigInt(getAddress20(b)) ? [getAddress20(a), getAddress20(b)] : [getAddress20(b), getAddress20(a)];
|
|
20962
21113
|
const pairKey = `${c0}-${c1}`;
|
|
20963
21114
|
const entry = this.#data.tokens[pairKey] ?? { searchedTo: "-1", pools: [] };
|
|
20964
21115
|
const head = await logsClient.getBlockNumber();
|
|
@@ -20970,7 +21121,7 @@ var init_pools2 = __esm({
|
|
|
20970
21121
|
const x = l.args;
|
|
20971
21122
|
if (x.id === void 0 || x.fee === void 0 || x.tickSpacing === void 0 || x.hooks === void 0 || seen.has(x.id)) continue;
|
|
20972
21123
|
seen.add(x.id);
|
|
20973
|
-
entry.pools.push({ id: x.id, key: { currency0: c0, currency1: c1, fee: x.fee, tickSpacing: x.tickSpacing, hooks:
|
|
21124
|
+
entry.pools.push({ id: x.id, key: { currency0: c0, currency1: c1, fee: x.fee, tickSpacing: x.tickSpacing, hooks: getAddress20(x.hooks) } });
|
|
20974
21125
|
}
|
|
20975
21126
|
entry.searchedTo = to.toString();
|
|
20976
21127
|
from = to + 1n;
|
|
@@ -20983,9 +21134,9 @@ var init_pools2 = __esm({
|
|
|
20983
21134
|
});
|
|
20984
21135
|
|
|
20985
21136
|
// ../../ostra-swap/sdk/src/route.ts
|
|
20986
|
-
import { decodeAbiParameters as decodeAbiParameters3, decodeFunctionResult as decodeFunctionResult3, encodeDeployData as encodeDeployData2, encodeFunctionData as encodeFunctionData10, getAddress as
|
|
21137
|
+
import { decodeAbiParameters as decodeAbiParameters3, decodeFunctionResult as decodeFunctionResult3, encodeDeployData as encodeDeployData2, encodeFunctionData as encodeFunctionData10, getAddress as getAddress21 } from "viem";
|
|
20987
21138
|
function routedToken(token) {
|
|
20988
|
-
const t =
|
|
21139
|
+
const t = getAddress21(token);
|
|
20989
21140
|
return t === ETH ? WETH2 : t;
|
|
20990
21141
|
}
|
|
20991
21142
|
function quoteCall(pool, tokenIn, tokenOut, amountIn) {
|
|
@@ -21083,8 +21234,8 @@ async function findRoute(r) {
|
|
|
21083
21234
|
}
|
|
21084
21235
|
if (best === null || expectedOut > best.expectedOut) {
|
|
21085
21236
|
best = {
|
|
21086
|
-
tokenIn:
|
|
21087
|
-
tokenOut:
|
|
21237
|
+
tokenIn: getAddress21(r.tokenIn),
|
|
21238
|
+
tokenOut: getAddress21(r.tokenOut),
|
|
21088
21239
|
amountIn: r.amountIn,
|
|
21089
21240
|
hub,
|
|
21090
21241
|
legIn,
|
|
@@ -21133,7 +21284,7 @@ var init_route = __esm({
|
|
|
21133
21284
|
});
|
|
21134
21285
|
|
|
21135
21286
|
// ../../ostra-swap/sdk/src/orders.ts
|
|
21136
|
-
import { encodeAbiParameters as
|
|
21287
|
+
import { encodeAbiParameters as encodeAbiParameters9, encodeFunctionData as encodeFunctionData11, getAddress as getAddress22, getContractAddress as getContractAddress3, isAddress as isAddress11, keccak256 as keccak25613, toHex as toHex5 } from "viem";
|
|
21137
21288
|
function parseSwapDeployment(json) {
|
|
21138
21289
|
const r = json;
|
|
21139
21290
|
if (r === null || typeof r !== "object") throw new Error("the deployment record is not a JSON object");
|
|
@@ -21142,22 +21293,22 @@ function parseSwapDeployment(json) {
|
|
|
21142
21293
|
const addr2 = (name) => {
|
|
21143
21294
|
const v = r[name];
|
|
21144
21295
|
if (typeof v !== "string" || !isAddress11(v, { strict: false })) throw new Error(`the deployment record has no ${name} address`);
|
|
21145
|
-
return
|
|
21296
|
+
return getAddress22(v);
|
|
21146
21297
|
};
|
|
21147
21298
|
return { chainId: r.chainId, fromBlock: r.fromBlock, router: addr2("router"), stake: addr2("stake"), buyback: addr2("buyback"), spendVerifier: addr2("spendVerifier"), privatePool: addr2("privatePool") };
|
|
21148
21299
|
}
|
|
21149
21300
|
function routeHash(hub, legIn, legOut) {
|
|
21150
|
-
return
|
|
21301
|
+
return keccak25613(encodeAbiParameters9([{ type: "address" }, legParam, legParam], [getAddress22(hub), legIn, legOut]));
|
|
21151
21302
|
}
|
|
21152
21303
|
function orderHash(order) {
|
|
21153
|
-
return
|
|
21304
|
+
return keccak25613(encodeAbiParameters9([orderParam], [order]));
|
|
21154
21305
|
}
|
|
21155
21306
|
function escrowAddress(router, order) {
|
|
21156
|
-
return getContractAddress3({ opcode: "CREATE2", from:
|
|
21307
|
+
return getContractAddress3({ opcode: "CREATE2", from: getAddress22(router), salt: orderHash(order), bytecode: OSTRA_SWAP_ESCROW_CREATION_CODE });
|
|
21157
21308
|
}
|
|
21158
21309
|
function orderFor(route, vault, vaultToken, recipient, now3, salt, ttlSeconds = DEFAULT_ORDER_TTL_SECONDS) {
|
|
21159
21310
|
if (route.tokenIn === ETH || route.tokenOut === ETH) throw new Error("a vault swaps ERC-20 tokens: WETH, not native ETH");
|
|
21160
|
-
if (
|
|
21311
|
+
if (getAddress22(vaultToken) !== getAddress22(route.tokenIn)) throw new Error(`the vault holds ${vaultToken}, not the route's tokenIn ${route.tokenIn}`);
|
|
21161
21312
|
if (!/^0x[0-9a-fA-F]{64}$/.test(salt)) throw new Error("the salt is 32 bytes");
|
|
21162
21313
|
const { legIn, legOut } = routeLegs(route);
|
|
21163
21314
|
return {
|
|
@@ -21165,8 +21316,8 @@ function orderFor(route, vault, vaultToken, recipient, now3, salt, ttlSeconds =
|
|
|
21165
21316
|
tokenOut: route.tokenOut,
|
|
21166
21317
|
amountIn: route.amountIn,
|
|
21167
21318
|
minOut: route.minOut,
|
|
21168
|
-
recipient:
|
|
21169
|
-
refundTo:
|
|
21319
|
+
recipient: getAddress22(recipient),
|
|
21320
|
+
refundTo: getAddress22(vault),
|
|
21170
21321
|
notBefore: 0n,
|
|
21171
21322
|
deadline: now3 + BigInt(ttlSeconds),
|
|
21172
21323
|
tranches: 0,
|
|
@@ -21178,7 +21329,7 @@ function orderFor(route, vault, vaultToken, recipient, now3, salt, ttlSeconds =
|
|
|
21178
21329
|
};
|
|
21179
21330
|
}
|
|
21180
21331
|
function randomSalt2() {
|
|
21181
|
-
return
|
|
21332
|
+
return toHex5(crypto.getRandomValues(new Uint8Array(32)));
|
|
21182
21333
|
}
|
|
21183
21334
|
function executeEscrowData(order, route) {
|
|
21184
21335
|
const { legIn, legOut } = routeLegs(route);
|
|
@@ -21226,7 +21377,7 @@ var init_orders = __esm({
|
|
|
21226
21377
|
});
|
|
21227
21378
|
|
|
21228
21379
|
// ../../ostra-swap/sdk/src/private.ts
|
|
21229
|
-
import { encodeAbiParameters as
|
|
21380
|
+
import { encodeAbiParameters as encodeAbiParameters10, encodeFunctionData as encodeFunctionData12, getAbiItem, getAddress as getAddress23, getContractAddress as getContractAddress4, keccak256 as keccak25614, parseEventLogs, toHex as toHex6 } from "viem";
|
|
21230
21381
|
function packDigest(elements) {
|
|
21231
21382
|
if (elements.length !== 8) throw new Error("a digest has 8 field elements");
|
|
21232
21383
|
let v = 0n;
|
|
@@ -21235,7 +21386,7 @@ function packDigest(elements) {
|
|
|
21235
21386
|
if (x < 0n || x >= FIELD_P) throw new Error("a digest element is not below P");
|
|
21236
21387
|
v |= x << BigInt(32 * i);
|
|
21237
21388
|
});
|
|
21238
|
-
return
|
|
21389
|
+
return toHex6(v, { size: 32 });
|
|
21239
21390
|
}
|
|
21240
21391
|
function unpackDigest(d) {
|
|
21241
21392
|
if (!/^0x[0-9a-fA-F]{64}$/.test(d)) throw new Error("a digest is 32 bytes");
|
|
@@ -21252,7 +21403,7 @@ function digestOf(v, what) {
|
|
|
21252
21403
|
}
|
|
21253
21404
|
async function noteKeys(prover, sk, rho, asset, amount) {
|
|
21254
21405
|
if (amount < 0n || amount >= MAX_AMOUNT) throw new Error("an amount is below 2^128");
|
|
21255
|
-
const r = await prover("note", { sk: unpackDigest(sk), rho: unpackDigest(rho), asset:
|
|
21406
|
+
const r = await prover("note", { sk: unpackDigest(sk), rho: unpackDigest(rho), asset: getAddress23(asset), amount: amount.toString() });
|
|
21256
21407
|
return { tag: digestOf(r.tag, "tag"), commitment: digestOf(r.commitment, "commitment"), nullifier: digestOf(r.nullifier, "nullifier") };
|
|
21257
21408
|
}
|
|
21258
21409
|
async function tagOf(prover, sk, rho) {
|
|
@@ -21281,16 +21432,16 @@ async function notePath(prover, trees, note) {
|
|
|
21281
21432
|
return { root, path: r.path };
|
|
21282
21433
|
}
|
|
21283
21434
|
function unshieldHash(chainId, pool, relayer, deadline, recipient) {
|
|
21284
|
-
return
|
|
21285
|
-
|
|
21435
|
+
return keccak25614(
|
|
21436
|
+
encodeAbiParameters10(
|
|
21286
21437
|
[{ type: "bytes32" }, { type: "uint256" }, { type: "address" }, { type: "address" }, { type: "uint64" }, { type: "address" }],
|
|
21287
|
-
[UNSHIELD_DOMAIN, BigInt(chainId),
|
|
21438
|
+
[UNSHIELD_DOMAIN, BigInt(chainId), getAddress23(pool), getAddress23(relayer), deadline, getAddress23(recipient)]
|
|
21288
21439
|
)
|
|
21289
21440
|
);
|
|
21290
21441
|
}
|
|
21291
21442
|
function swapHash(chainId, pool, relayer, deadline, t) {
|
|
21292
|
-
return
|
|
21293
|
-
|
|
21443
|
+
return keccak25614(
|
|
21444
|
+
encodeAbiParameters10(
|
|
21294
21445
|
[
|
|
21295
21446
|
{ type: "bytes32" },
|
|
21296
21447
|
{ type: "uint256" },
|
|
@@ -21302,7 +21453,7 @@ function swapHash(chainId, pool, relayer, deadline, t) {
|
|
|
21302
21453
|
{ type: "bytes32" },
|
|
21303
21454
|
{ type: "bytes32" }
|
|
21304
21455
|
],
|
|
21305
|
-
[SWAP_DOMAIN, BigInt(chainId),
|
|
21456
|
+
[SWAP_DOMAIN, BigInt(chainId), getAddress23(pool), getAddress23(relayer), deadline, getAddress23(t.tokenOut), t.minOut, t.outTag, routeHash(t.hub, t.legIn, t.legOut)]
|
|
21306
21457
|
)
|
|
21307
21458
|
);
|
|
21308
21459
|
}
|
|
@@ -21312,7 +21463,7 @@ function publicValues(asset, v, fee, nullifier, root, changeCommitment, bindHash
|
|
|
21312
21463
|
const words = (d) => unpackDigest(d).map((x) => BigInt(x));
|
|
21313
21464
|
const h = BigInt(bindHash);
|
|
21314
21465
|
return [
|
|
21315
|
-
...limbs(BigInt(
|
|
21466
|
+
...limbs(BigInt(getAddress23(asset)), 6, 27),
|
|
21316
21467
|
...limbs(v, 5, 26),
|
|
21317
21468
|
...limbs(fee, 5, 26),
|
|
21318
21469
|
...words(nullifier),
|
|
@@ -21325,7 +21476,7 @@ async function prove(r, v, bindHash, recipient) {
|
|
|
21325
21476
|
const n = r.note;
|
|
21326
21477
|
if (r.changeRho !== void 0 && r.changeRho.toLowerCase() === n.rho.toLowerCase()) throw new Error("changeRho must be a fresh secret, not the note's rho");
|
|
21327
21478
|
if (v < 0n || r.fee < 0n || v + r.fee > n.amount) throw new Error(`the note holds ${n.amount}, less than ${v} + ${r.fee}`);
|
|
21328
|
-
if (r.fee !== 0n &&
|
|
21479
|
+
if (r.fee !== 0n && getAddress23(r.relayer) === ZERO2) throw new Error("a fee needs a relayer");
|
|
21329
21480
|
if (r.deadline < 0n || r.deadline > MAX_UINT642) throw new Error("the deadline is uint64 unix seconds");
|
|
21330
21481
|
const keys = await noteKeys(r.prover, r.sk, n.rho, n.asset, n.amount);
|
|
21331
21482
|
if (keys.commitment.toLowerCase() !== n.commitment.toLowerCase()) throw new Error("the note is not this sk's (or its rho, token or amount is wrong)");
|
|
@@ -21333,7 +21484,7 @@ async function prove(r, v, bindHash, recipient) {
|
|
|
21333
21484
|
const out = await r.prover("prove", {
|
|
21334
21485
|
sk: unpackDigest(r.sk),
|
|
21335
21486
|
rho: unpackDigest(n.rho),
|
|
21336
|
-
asset:
|
|
21487
|
+
asset: getAddress23(n.asset),
|
|
21337
21488
|
amount: n.amount.toString(),
|
|
21338
21489
|
index: n.index,
|
|
21339
21490
|
path,
|
|
@@ -21346,7 +21497,7 @@ async function prove(r, v, bindHash, recipient) {
|
|
|
21346
21497
|
if (typeof out.proof !== "string" || !/^0x[0-9a-f]*$/.test(out.proof) || !Array.isArray(out.public_values) || out.public_values.length !== 48) throw new Error("ostra-prove gave no proof");
|
|
21347
21498
|
const pv = out.public_values.map((x) => BigInt(x));
|
|
21348
21499
|
const changeCommitment = packDigest(pv.slice(32, 40));
|
|
21349
|
-
const terms = { asset:
|
|
21500
|
+
const terms = { asset: getAddress23(n.asset), v, fee: r.fee, nullifier: keys.nullifier, root, changeCommitment, relayer: getAddress23(r.relayer), deadline: r.deadline };
|
|
21350
21501
|
const want = publicValues(terms.asset, v, r.fee, terms.nullifier, root, changeCommitment, bindHash);
|
|
21351
21502
|
if (want.some((x, i) => x !== pv[i])) throw new Error("the proof's public values are not the spend's");
|
|
21352
21503
|
const changeRho = digestOf(out.change_rho, "change_rho");
|
|
@@ -21356,40 +21507,40 @@ async function prove(r, v, bindHash, recipient) {
|
|
|
21356
21507
|
return { terms, proof: out.proof, recipient, change: { rho: changeRho, amount: change, commitment: changeCommitment } };
|
|
21357
21508
|
}
|
|
21358
21509
|
async function proveUnshield(r) {
|
|
21359
|
-
if (
|
|
21360
|
-
return prove(r, r.v, unshieldHash(r.chainId, r.pool, r.relayer, r.deadline, r.recipient),
|
|
21510
|
+
if (getAddress23(r.recipient) === ZERO2) throw new Error("an unshield needs a recipient");
|
|
21511
|
+
return prove(r, r.v, unshieldHash(r.chainId, r.pool, r.relayer, r.deadline, r.recipient), getAddress23(r.recipient));
|
|
21361
21512
|
}
|
|
21362
21513
|
async function provePrivateSwap(r) {
|
|
21363
21514
|
const route = r.route;
|
|
21364
21515
|
if (route.feeBps !== PRIVATE_SWAP_FEE_BPS) throw new Error(`a private swap pays the base fee: find its route with feeBps ${PRIVATE_SWAP_FEE_BPS}`);
|
|
21365
21516
|
if (route.tokenIn === ETH || route.tokenOut === ETH) throw new Error("notes hold ERC-20 tokens: WETH, not native ETH");
|
|
21366
|
-
if (
|
|
21517
|
+
if (getAddress23(route.tokenIn) !== getAddress23(r.note.asset)) throw new Error(`the route swaps ${route.tokenIn}, the note holds ${r.note.asset}`);
|
|
21367
21518
|
if (r.outRho.toLowerCase() === r.note.rho.toLowerCase()) throw new Error("outRho must be a fresh secret");
|
|
21368
21519
|
const { legIn, legOut } = routeLegs(route);
|
|
21369
|
-
const swap = { tokenOut:
|
|
21520
|
+
const swap = { tokenOut: getAddress23(route.tokenOut), minOut: route.minOut, outTag: await tagOf(r.prover, r.sk, r.outRho), hub: getAddress23(route.hub), legIn, legOut };
|
|
21370
21521
|
if (r.changeRho !== void 0 && r.changeRho.toLowerCase() === r.outRho.toLowerCase()) throw new Error("the change and the output share a rho");
|
|
21371
21522
|
const spend = await prove(r, route.amountIn, swapHash(r.chainId, r.pool, r.relayer, r.deadline, swap), null);
|
|
21372
21523
|
if (spend.change.rho.toLowerCase() === r.outRho.toLowerCase()) throw new Error("the change and the output share a rho");
|
|
21373
21524
|
return { spend, swap };
|
|
21374
21525
|
}
|
|
21375
21526
|
function shieldEscrowAddress(pool, token, tag) {
|
|
21376
|
-
const salt =
|
|
21377
|
-
return getContractAddress4({ opcode: "CREATE2", from:
|
|
21527
|
+
const salt = keccak25614(encodeAbiParameters10([{ type: "address" }, { type: "bytes32" }], [getAddress23(token), tag]));
|
|
21528
|
+
return getContractAddress4({ opcode: "CREATE2", from: getAddress23(pool), salt, bytecode: OSTRA_SHIELD_ESCROW_CREATION_CODE });
|
|
21378
21529
|
}
|
|
21379
21530
|
function shieldFromEscrowCall(pool, token, tag) {
|
|
21380
|
-
return { to:
|
|
21531
|
+
return { to: getAddress23(pool), data: encodeFunctionData12({ abi: ostraPrivatePoolAbi, functionName: "shieldFromEscrow", args: [getAddress23(token), tag] }) };
|
|
21381
21532
|
}
|
|
21382
21533
|
function unshieldCall(pool, spend, recipient) {
|
|
21383
|
-
if (spend.recipient === null || spend.recipient !==
|
|
21384
|
-
return { to:
|
|
21534
|
+
if (spend.recipient === null || spend.recipient !== getAddress23(recipient)) throw new Error("this spend was proved for another recipient (or is a swap)");
|
|
21535
|
+
return { to: getAddress23(pool), data: encodeFunctionData12({ abi: ostraPrivatePoolAbi, functionName: "unshield", args: [spend.terms, getAddress23(recipient), spend.proof] }) };
|
|
21385
21536
|
}
|
|
21386
21537
|
function privateSwapCall(pool, spend, swap) {
|
|
21387
21538
|
if (spend.recipient !== null) throw new Error("this spend was proved for an unshield");
|
|
21388
|
-
return { to:
|
|
21539
|
+
return { to: getAddress23(pool), data: encodeFunctionData12({ abi: ostraPrivatePoolAbi, functionName: "privateSwap", args: [spend.terms, swap, spend.proof] }) };
|
|
21389
21540
|
}
|
|
21390
21541
|
function poolEvents(receipt, pool) {
|
|
21391
21542
|
if (receipt.status !== "success") throw new Error("the transaction reverted");
|
|
21392
|
-
return parseEventLogs({ abi: ostraPrivatePoolAbi, logs: receipt.logs.filter((l) =>
|
|
21543
|
+
return parseEventLogs({ abi: ostraPrivatePoolAbi, logs: receipt.logs.filter((l) => getAddress23(l.address) === getAddress23(pool)) });
|
|
21393
21544
|
}
|
|
21394
21545
|
function placed(receipt, pool, commitment) {
|
|
21395
21546
|
for (const e of poolEvents(receipt, pool)) {
|
|
@@ -21401,7 +21552,7 @@ async function shieldedNote(prover, sk, rho, receipt, pool) {
|
|
|
21401
21552
|
const tag = (await tagOf(prover, sk, rho)).toLowerCase();
|
|
21402
21553
|
for (const e of poolEvents(receipt, pool)) {
|
|
21403
21554
|
if (e.eventName !== "Shielded" || e.args.tag.toLowerCase() !== tag) continue;
|
|
21404
|
-
const asset =
|
|
21555
|
+
const asset = getAddress23(e.args.token);
|
|
21405
21556
|
const keys = await noteKeys(prover, sk, rho, asset, e.args.amount);
|
|
21406
21557
|
if (keys.commitment.toLowerCase() !== e.args.commitment.toLowerCase()) throw new Error("the shielded commitment is not this note's");
|
|
21407
21558
|
return { asset, amount: e.args.amount, rho, commitment: e.args.commitment, ...placed(receipt, pool, e.args.commitment) };
|
|
@@ -21435,8 +21586,8 @@ var init_private = __esm({
|
|
|
21435
21586
|
FIELD_P = 2130706433n;
|
|
21436
21587
|
TREE_DEPTH = 20;
|
|
21437
21588
|
PRIVATE_SWAP_FEE_BPS = 20;
|
|
21438
|
-
UNSHIELD_DOMAIN =
|
|
21439
|
-
SWAP_DOMAIN =
|
|
21589
|
+
UNSHIELD_DOMAIN = keccak25614(toHex6("OstraPrivatePool.unshield.v1"));
|
|
21590
|
+
SWAP_DOMAIN = keccak25614(toHex6("OstraPrivatePool.privateSwap.v1"));
|
|
21440
21591
|
MAX_AMOUNT = 1n << 128n;
|
|
21441
21592
|
MAX_UINT642 = (1n << 64n) - 1n;
|
|
21442
21593
|
ZERO2 = "0x0000000000000000000000000000000000000000";
|
|
@@ -21449,9 +21600,9 @@ var init_private = __esm({
|
|
|
21449
21600
|
constructor(pool, fromBlock, data) {
|
|
21450
21601
|
if (data !== void 0) {
|
|
21451
21602
|
if (data.version !== 1) throw new Error("unknown trees version");
|
|
21452
|
-
if (
|
|
21603
|
+
if (getAddress23(data.pool) !== getAddress23(pool)) throw new Error("these trees are another pool's");
|
|
21453
21604
|
}
|
|
21454
|
-
this.#data = data ?? { version: 1, pool:
|
|
21605
|
+
this.#data = data ?? { version: 1, pool: getAddress23(pool), searchedTo: (fromBlock - 1n).toString(), trees: [] };
|
|
21455
21606
|
}
|
|
21456
21607
|
data() {
|
|
21457
21608
|
return this.#data;
|
|
@@ -21542,7 +21693,7 @@ var init_private = __esm({
|
|
|
21542
21693
|
});
|
|
21543
21694
|
|
|
21544
21695
|
// ../../ostra-swap/sdk/src/reads.ts
|
|
21545
|
-
import { getAddress as
|
|
21696
|
+
import { getAddress as getAddress24 } from "viem";
|
|
21546
21697
|
var init_reads2 = __esm({
|
|
21547
21698
|
"../../ostra-swap/sdk/src/reads.ts"() {
|
|
21548
21699
|
"use strict";
|
|
@@ -21569,9 +21720,9 @@ var init_src2 = __esm({
|
|
|
21569
21720
|
});
|
|
21570
21721
|
|
|
21571
21722
|
// ../core/src/private-balance.ts
|
|
21572
|
-
import { getAddress as
|
|
21723
|
+
import { getAddress as getAddress25, parseAbiItem as parseAbiItem4 } from "viem";
|
|
21573
21724
|
function privateTokens(config) {
|
|
21574
|
-
return [config.deployment.token, WETH, ...LAUNCH_PAIRS.filter((p) => p.kind === "ostra" || p.kind === "stock").map((p) =>
|
|
21725
|
+
return [config.deployment.token, WETH, ...LAUNCH_PAIRS.filter((p) => p.kind === "ostra" || p.kind === "stock").map((p) => getAddress25(p.address))];
|
|
21575
21726
|
}
|
|
21576
21727
|
var PRIVATE_SWAP_DIR, PRIVATE_SHIELD_GAS, PRIVATE_SPEND_DEADLINE_SECONDS, MAX_SLIPPAGE_BPS2, PRIVATE_FEE_GAS, PRIVATE_FEE_MAX_FACTOR, SHIELD_SCAN_GAP, LOGS_CATCH_UP_TRIES, SHIELD_LOG_WAIT_MS, NOTES, TREES, NEXT_RHO, POOL_INDEX, PENDING_PREFIX, shieldedEvent, swappedEvent, unshieldedEvent, address3, PrivateBalanceService;
|
|
21577
21728
|
var init_private_balance = __esm({
|
|
@@ -21605,7 +21756,7 @@ var init_private_balance = __esm({
|
|
|
21605
21756
|
unshieldedEvent = parseAbiItem4("event Unshielded(bytes32 indexed nullifier, address indexed recipient, address indexed token, uint256 amount, uint256 fee, address relayer)");
|
|
21606
21757
|
address3 = (text2, what) => {
|
|
21607
21758
|
if (!/^0x[0-9a-fA-F]{40}$/.test(text2)) throw new RangeError(`${what} is not an address`);
|
|
21608
|
-
return
|
|
21759
|
+
return getAddress25(text2);
|
|
21609
21760
|
};
|
|
21610
21761
|
PrivateBalanceService = class {
|
|
21611
21762
|
#p;
|
|
@@ -21615,7 +21766,7 @@ var init_private_balance = __esm({
|
|
|
21615
21766
|
#tail = Promise.resolve();
|
|
21616
21767
|
constructor(p) {
|
|
21617
21768
|
this.#p = p;
|
|
21618
|
-
this.#pool =
|
|
21769
|
+
this.#pool = getAddress25(p.swap.privatePool);
|
|
21619
21770
|
}
|
|
21620
21771
|
get pool() {
|
|
21621
21772
|
return this.#pool;
|
|
@@ -21680,27 +21831,37 @@ var init_private_balance = __esm({
|
|
|
21680
21831
|
for (const l of await this.#poolLogs(from, to)) {
|
|
21681
21832
|
if (l.eventName === "Shielded") {
|
|
21682
21833
|
const tag = l.args.tag.toLowerCase();
|
|
21683
|
-
shielded.set(tag, [...shielded.get(tag) ?? [], { token:
|
|
21834
|
+
shielded.set(tag, [...shielded.get(tag) ?? [], { token: getAddress25(l.args.token), amount: l.args.amount, commitment: l.args.commitment }]);
|
|
21684
21835
|
notes += 1;
|
|
21685
21836
|
} else if (l.eventName === "Unshielded") {
|
|
21686
21837
|
spends.set(l.args.nullifier.toLowerCase(), { kind: "unshield", v: l.args.amount, fee: l.args.fee });
|
|
21687
21838
|
notes += 1;
|
|
21688
21839
|
} else {
|
|
21689
|
-
spends.set(l.args.nullifier.toLowerCase(), { kind: "swap", v: l.args.amountIn, fee: l.args.fee, tokenOut:
|
|
21840
|
+
spends.set(l.args.nullifier.toLowerCase(), { kind: "swap", v: l.args.amountIn, fee: l.args.fee, tokenOut: getAddress25(l.args.tokenOut), amountOut: l.args.amountOut, outCommitment: l.args.outCommitment });
|
|
21690
21841
|
notes += 2;
|
|
21691
21842
|
}
|
|
21692
21843
|
}
|
|
21693
21844
|
}
|
|
21694
21845
|
return { shielded, spends, notes };
|
|
21695
21846
|
}
|
|
21696
|
-
/**
|
|
21847
|
+
/**
|
|
21848
|
+
* The pool's Shielded, Unshielded and PrivateSwapped logs in [from, to], one event per request: Robinhood Chain's
|
|
21849
|
+
* public RPC serves LOG_WINDOW_BLOCKS only for one value per topic position, and a request naming the three events
|
|
21850
|
+
* at once over at most 100,000 blocks (measured 23 Oct 2026, error -32602).
|
|
21851
|
+
*/
|
|
21697
21852
|
async #poolLogs(from, to) {
|
|
21853
|
+
const out = [];
|
|
21854
|
+
for (const event of [shieldedEvent, unshieldedEvent, swappedEvent]) out.push(...await this.#eventLogs(event, from, to));
|
|
21855
|
+
return out;
|
|
21856
|
+
}
|
|
21857
|
+
/** The pool's logs of `event` in [from, to]; a range the RPC refuses as too many logs is split in halves. */
|
|
21858
|
+
async #eventLogs(event, from, to) {
|
|
21698
21859
|
try {
|
|
21699
|
-
return await this.#p.logsClient.getLogs({ address: this.#pool,
|
|
21860
|
+
return await this.#p.logsClient.getLogs({ address: this.#pool, event, fromBlock: from, toBlock: to, strict: true });
|
|
21700
21861
|
} catch (err) {
|
|
21701
21862
|
if (from >= to || !/exceeds limit|too many|query returned more than/i.test(String(err.message ?? err))) throw err;
|
|
21702
21863
|
const mid = from + (to - from) / 2n;
|
|
21703
|
-
return [...await this.#
|
|
21864
|
+
return [...await this.#eventLogs(event, from, mid), ...await this.#eventLogs(event, mid + 1n, to)];
|
|
21704
21865
|
}
|
|
21705
21866
|
}
|
|
21706
21867
|
/** Rebuilds the agent's notes from the seed and the pool's events (see the file comment); the notes kept here become the unspent ones found. */
|
|
@@ -21784,7 +21945,7 @@ var init_private_balance = __esm({
|
|
|
21784
21945
|
const found = new Set(unspent.map((n) => n.commitment.toLowerCase()));
|
|
21785
21946
|
const local = [];
|
|
21786
21947
|
for (const n of await this.#notes()) {
|
|
21787
|
-
if (found.has(n.commitment.toLowerCase()) || !tokens.has(
|
|
21948
|
+
if (found.has(n.commitment.toLowerCase()) || !tokens.has(getAddress25(n.asset)) || trees.find(n.commitment) === null) continue;
|
|
21788
21949
|
const keys = await noteKeys(prover, sk, n.rho, n.asset, BigInt(n.amount));
|
|
21789
21950
|
if (keys.commitment.toLowerCase() === n.commitment.toLowerCase() && !events.spends.has(keys.nullifier.toLowerCase())) local.push(n);
|
|
21790
21951
|
}
|
|
@@ -21942,7 +22103,7 @@ var init_private_balance = __esm({
|
|
|
21942
22103
|
const body = await this.#http("GET", `${url}/v1/private/price?token=${token}&kind=${kind}`);
|
|
21943
22104
|
const b = body;
|
|
21944
22105
|
if (typeof b.fee !== "string" || !/^[0-9]+$/.test(b.fee) || typeof b.relayer !== "string") throw new Error("the relayer's private price has no fee or relayer");
|
|
21945
|
-
return { fee: BigInt(b.fee), relayer:
|
|
22106
|
+
return { fee: BigInt(b.fee), relayer: getAddress25(b.relayer) };
|
|
21946
22107
|
}
|
|
21947
22108
|
async #http(method, url, body) {
|
|
21948
22109
|
let res;
|
|
@@ -22195,7 +22356,7 @@ var init_seed_backup = __esm({
|
|
|
22195
22356
|
});
|
|
22196
22357
|
|
|
22197
22358
|
// ../core/src/sessions.ts
|
|
22198
|
-
import { bytesToHex as bytesToHex12, getAddress as
|
|
22359
|
+
import { bytesToHex as bytesToHex12, getAddress as getAddress26, isAddress as isAddress12 } from "viem";
|
|
22199
22360
|
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
22200
22361
|
var init_sessions = __esm({
|
|
22201
22362
|
"../core/src/sessions.ts"() {
|
|
@@ -22207,19 +22368,19 @@ var init_sessions = __esm({
|
|
|
22207
22368
|
});
|
|
22208
22369
|
|
|
22209
22370
|
// ../core/src/shield.ts
|
|
22210
|
-
import { bytesToHex as bytesToHex13, encodeFunctionData as encodeFunctionData13, getAddress as
|
|
22371
|
+
import { bytesToHex as bytesToHex13, encodeFunctionData as encodeFunctionData13, getAddress as getAddress27, hexToBytes as hexToBytes8, parseSignature } from "viem";
|
|
22211
22372
|
function leafKeyIndex(attempt, j) {
|
|
22212
22373
|
if (!Number.isInteger(attempt) || attempt < 0 || attempt >= MAX_LEAF_ATTEMPTS) throw new RangeError(`leaf set ${String(attempt)} is out of range`);
|
|
22213
22374
|
if (!Number.isInteger(j) || j < 0 || j >= LEAF_KEYS_PER_ATTEMPT) throw new RangeError(`leaf ${String(j)} is out of range`);
|
|
22214
22375
|
return attempt * LEAF_KEYS_PER_ATTEMPT + j;
|
|
22215
22376
|
}
|
|
22216
22377
|
function recordName(chainId, token, index) {
|
|
22217
|
-
return `${chainId}-${
|
|
22378
|
+
return `${chainId}-${getAddress27(token)}-${index}.json`;
|
|
22218
22379
|
}
|
|
22219
22380
|
function decodeApproveMessage(message) {
|
|
22220
22381
|
if (message.length !== APPROVE_MESSAGE_LEN) throw new Error("not an approval message");
|
|
22221
22382
|
const chainId = Number(BigInt(bytesToHex13(message.subarray(20, 52))));
|
|
22222
|
-
const pool =
|
|
22383
|
+
const pool = getAddress27(bytesToHex13(message.subarray(52, 72)));
|
|
22223
22384
|
const key = bytesToHex13(message.subarray(72, 104));
|
|
22224
22385
|
const batchId = BigInt(bytesToHex13(message.subarray(104, 112)));
|
|
22225
22386
|
const state = bytesToHex13(message.subarray(112, 144));
|
|
@@ -22294,7 +22455,7 @@ var init_shield = __esm({
|
|
|
22294
22455
|
/** True when `record` belongs to this service's vault. */
|
|
22295
22456
|
async #mine(record) {
|
|
22296
22457
|
if (record.vault === void 0) return this.#vault.kind === "buyer";
|
|
22297
|
-
return
|
|
22458
|
+
return getAddress27(record.vault) === await this.#vault.vaultAddress();
|
|
22298
22459
|
}
|
|
22299
22460
|
/** A new record under the first free deposit number (created exclusively: another vault's service may be creating one too). */
|
|
22300
22461
|
async #createRecord(make) {
|
|
@@ -22455,8 +22616,8 @@ var init_shield = __esm({
|
|
|
22455
22616
|
const { batchCount } = await readPool(this.#client, this.#pool());
|
|
22456
22617
|
const health = await this.#aggregator("GET", "/v1/health");
|
|
22457
22618
|
if (typeof health.aggregator !== "string") throw new Error("the aggregator's health names no aggregator account");
|
|
22458
|
-
const aggregator =
|
|
22459
|
-
const accounts = /* @__PURE__ */ new Set([...(record.aggregators ?? []).map((a) =>
|
|
22619
|
+
const aggregator = getAddress27(health.aggregator);
|
|
22620
|
+
const accounts = /* @__PURE__ */ new Set([...(record.aggregators ?? []).map((a) => getAddress27(a)), aggregator]);
|
|
22460
22621
|
if (accounts.size !== (record.aggregators ?? []).length) {
|
|
22461
22622
|
record.aggregators = [...accounts];
|
|
22462
22623
|
await this.#save(record);
|
|
@@ -22511,11 +22672,11 @@ var init_shield = __esm({
|
|
|
22511
22672
|
const room = await this.#room(p.maxTotal);
|
|
22512
22673
|
if (amount > room) throw new RangeError(`the pool has room for ${formatTokenAmount(room)} more, and a deposit of ${leaves} leaves is ${formatTokenAmount(amount)}; nothing was signed`);
|
|
22513
22674
|
const terms = await this.#aggregator("GET", "/v1/terms");
|
|
22514
|
-
if (terms.chainId !== this.#config.chainId || typeof terms.pool !== "string" ||
|
|
22675
|
+
if (terms.chainId !== this.#config.chainId || typeof terms.pool !== "string" || getAddress27(terms.pool) !== pool || typeof terms.token !== "string" || getAddress27(terms.token) !== this.#token()) {
|
|
22515
22676
|
throw new Error(`the aggregator serves pool ${String(terms.pool)} on chain ${String(terms.chainId)}, not ${pool} on ${this.#config.chainId}`);
|
|
22516
22677
|
}
|
|
22517
22678
|
if (typeof terms.aggregator !== "string") throw new Error("the aggregator's terms name no aggregator account");
|
|
22518
|
-
const aggregatorAccount =
|
|
22679
|
+
const aggregatorAccount = getAddress27(terms.aggregator);
|
|
22519
22680
|
const status = await this.#vault.status();
|
|
22520
22681
|
if (!status.vaultExists) throw new Error("open the vault and fund it first (open_vault)");
|
|
22521
22682
|
const vault = await this.#vault.vaultAddress();
|
|
@@ -22772,7 +22933,7 @@ var init_shield = __esm({
|
|
|
22772
22933
|
leavesInPool.push({ batch: r.batch, leafIndex: i, key: leafKeyIndex(r.attempt ?? 0, j), amount: formatTokenAmount(LEAF_DENOMINATION), spent: b.status === "none" || leaf === void 0 || leaf.spent });
|
|
22773
22934
|
});
|
|
22774
22935
|
}
|
|
22775
|
-
out.push({ index: r.index, vault: r.vault === void 0 ? null :
|
|
22936
|
+
out.push({ index: r.index, vault: r.vault === void 0 ? null : getAddress27(r.vault), deposit: r.deposit, leaves: r.leaves, amount: formatTokenAmount(BigInt(r.amount)), status: r.status, batch: r.batch, leavesInPool });
|
|
22776
22937
|
}
|
|
22777
22938
|
return out;
|
|
22778
22939
|
});
|
|
@@ -22790,7 +22951,7 @@ var init_storage = __esm({
|
|
|
22790
22951
|
});
|
|
22791
22952
|
|
|
22792
22953
|
// ../core/src/swap.ts
|
|
22793
|
-
import { decodeEventLog as decodeEventLog4, getAddress as
|
|
22954
|
+
import { decodeEventLog as decodeEventLog4, getAddress as getAddress28 } from "viem";
|
|
22794
22955
|
var SWAP_DIR, ESCROW_SWAP_GAS, DEFAULT_SWAP_SLIPPAGE_BPS, MAX_SWAP_SLIPPAGE_BPS, POOL_INDEX2, ORDER_PREFIX, address4, SwapService;
|
|
22795
22956
|
var init_swap = __esm({
|
|
22796
22957
|
"../core/src/swap.ts"() {
|
|
@@ -22810,7 +22971,7 @@ var init_swap = __esm({
|
|
|
22810
22971
|
ORDER_PREFIX = "order-";
|
|
22811
22972
|
address4 = (text2, what) => {
|
|
22812
22973
|
if (!/^0x[0-9a-fA-F]{40}$/.test(text2)) throw new RangeError(`${what} is not an address`);
|
|
22813
|
-
return
|
|
22974
|
+
return getAddress28(text2);
|
|
22814
22975
|
};
|
|
22815
22976
|
SwapService = class {
|
|
22816
22977
|
#p;
|
|
@@ -22834,7 +22995,7 @@ var init_swap = __esm({
|
|
|
22834
22995
|
async checkToken(token) {
|
|
22835
22996
|
if (token === ETH) throw new RangeError("an Ostra vault holds WETH, not native ETH: swap WETH");
|
|
22836
22997
|
if (token === this.#p.config.deployment.token || token === WETH) return;
|
|
22837
|
-
if (LAUNCH_PAIRS.some((p) => (p.kind === "ostra" || p.kind === "stock") &&
|
|
22998
|
+
if (LAUNCH_PAIRS.some((p) => (p.kind === "ostra" || p.kind === "stock") && getAddress28(p.address) === token)) return;
|
|
22838
22999
|
const lp = this.#p.config.deployment.launchpad;
|
|
22839
23000
|
if (lp !== void 0) {
|
|
22840
23001
|
const id = await this.#p.client.readContract({ address: lp.launchpad, abi: ostraLaunchpadAbi, functionName: "poolOf", args: [token] });
|
|
@@ -22934,7 +23095,7 @@ var init_swap = __esm({
|
|
|
22934
23095
|
let swapped = null;
|
|
22935
23096
|
let amountOut = 0n;
|
|
22936
23097
|
for (const log2 of receipt.logs) {
|
|
22937
|
-
if (
|
|
23098
|
+
if (getAddress28(log2.address) !== getAddress28(this.#p.swap.router)) continue;
|
|
22938
23099
|
try {
|
|
22939
23100
|
const e = decodeEventLog4({ abi: ostraRouterAbi, topics: log2.topics, data: log2.data });
|
|
22940
23101
|
if (e.eventName === "EscrowExecuted" && e.args.orderHash.toLowerCase() === hash.toLowerCase()) swapped = e.args.swapped;
|
|
@@ -22977,9 +23138,9 @@ var init_swap = __esm({
|
|
|
22977
23138
|
});
|
|
22978
23139
|
|
|
22979
23140
|
// ../core/src/unshield.ts
|
|
22980
|
-
import { encodeFunctionData as encodeFunctionData14, getAddress as
|
|
23141
|
+
import { encodeFunctionData as encodeFunctionData14, getAddress as getAddress29 } from "viem";
|
|
22981
23142
|
function recordName2(chainId, token, index) {
|
|
22982
|
-
return `${chainId}-${
|
|
23143
|
+
return `${chainId}-${getAddress29(token)}-${index}.json`;
|
|
22983
23144
|
}
|
|
22984
23145
|
function unshieldDelaySeconds(windowHours) {
|
|
22985
23146
|
if (!Number.isFinite(windowHours) || windowHours < 0 || windowHours > UNSHIELD_MAX_WINDOW_HOURS) {
|
|
@@ -23052,7 +23213,7 @@ var init_unshield = __esm({
|
|
|
23052
23213
|
}
|
|
23053
23214
|
/** The private vaults created so far (their leaf spent), by index. */
|
|
23054
23215
|
vaults() {
|
|
23055
|
-
return this.#serial(async () => (await this.#records()).filter((r) => r.status === "spent").map((r) => ({ index: BigInt(r.index), vault:
|
|
23216
|
+
return this.#serial(async () => (await this.#records()).filter((r) => r.status === "spent").map((r) => ({ index: BigInt(r.index), vault: getAddress29(r.vault) })));
|
|
23056
23217
|
}
|
|
23057
23218
|
/** The number of the private vault at `vault`, or throws when it is none of this agent's. */
|
|
23058
23219
|
async indexOf(vault) {
|
|
@@ -23151,7 +23312,7 @@ var init_unshield = __esm({
|
|
|
23151
23312
|
async #spend(r) {
|
|
23152
23313
|
const ctx = await this.#context(BigInt(r.index));
|
|
23153
23314
|
const vault = await ctx.vault.vaultAddress();
|
|
23154
|
-
if (vault !==
|
|
23315
|
+
if (vault !== getAddress29(r.vault)) throw new Error(`private vault ${r.index} is ${vault}, not the recorded ${r.vault}`);
|
|
23155
23316
|
const pool = this.#config.deployment.pool;
|
|
23156
23317
|
const batch = await readBatch(this.#client, pool, BigInt(r.batch));
|
|
23157
23318
|
const leaf = batch.leaves[r.leafIndex];
|
|
@@ -23188,9 +23349,9 @@ var init_unshield = __esm({
|
|
|
23188
23349
|
import {
|
|
23189
23350
|
concatHex as concatHex2,
|
|
23190
23351
|
decodeErrorResult as decodeErrorResult2,
|
|
23191
|
-
encodeAbiParameters as
|
|
23352
|
+
encodeAbiParameters as encodeAbiParameters11,
|
|
23192
23353
|
encodeFunctionData as encodeFunctionData15,
|
|
23193
|
-
getAddress as
|
|
23354
|
+
getAddress as getAddress30,
|
|
23194
23355
|
maxUint256,
|
|
23195
23356
|
parseAbi as parseAbi4,
|
|
23196
23357
|
zeroAddress as zeroAddress12
|
|
@@ -23227,6 +23388,7 @@ var init_src3 = __esm({
|
|
|
23227
23388
|
"../core/src/index.ts"() {
|
|
23228
23389
|
"use strict";
|
|
23229
23390
|
init_define_OSTRA_PACKAGED();
|
|
23391
|
+
init_ai();
|
|
23230
23392
|
init_amount();
|
|
23231
23393
|
init_chain2();
|
|
23232
23394
|
init_channels();
|
|
@@ -23547,7 +23709,7 @@ var init_wasm_prover = __esm({
|
|
|
23547
23709
|
// src/agent.ts
|
|
23548
23710
|
import { readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
23549
23711
|
import { join as join5 } from "node:path";
|
|
23550
|
-
import { createPublicClient as createPublicClient2, getAddress as
|
|
23712
|
+
import { createPublicClient as createPublicClient2, getAddress as getAddress31, http as http2, isAddress as isAddress13 } from "viem";
|
|
23551
23713
|
import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
|
|
23552
23714
|
function proverOf(c) {
|
|
23553
23715
|
if (c === null) return null;
|
|
@@ -23607,6 +23769,8 @@ var init_agent = __esm({
|
|
|
23607
23769
|
shield;
|
|
23608
23770
|
creatorShield;
|
|
23609
23771
|
unshield;
|
|
23772
|
+
/** Ostra AI's tasks paid from the vault (null without OSTRA_AI_URL). */
|
|
23773
|
+
ai;
|
|
23610
23774
|
/** Ostra Swap from the agent's vaults, and its private notes (null without OSTRA_SWAP_DEPLOYMENT). */
|
|
23611
23775
|
swap;
|
|
23612
23776
|
privateBalance;
|
|
@@ -23629,6 +23793,7 @@ var init_agent = __esm({
|
|
|
23629
23793
|
this.relayer?.attachBuyerVault(this.buyer);
|
|
23630
23794
|
this.channels = new ChannelService(client, config, keys, this.buyer, this.sender);
|
|
23631
23795
|
this.payments = new PayService(client, config, this.buyer, this.channels);
|
|
23796
|
+
this.ai = config.aiUrl === null ? null : new AiService(config, this.payments, this.buyer);
|
|
23632
23797
|
this.seller = new VaultService(client, transport, config, keys, this.sender, "seller");
|
|
23633
23798
|
this.creatorRelayer = config.relayerUrl === null ? null : new RelayerClient(client, config, p.creatorKeys, config.relayerUrl);
|
|
23634
23799
|
const creatorSender = this.creatorRelayer ?? this.local;
|
|
@@ -23662,7 +23827,7 @@ var init_agent = __esm({
|
|
|
23662
23827
|
}
|
|
23663
23828
|
/** The agent's vault for `token`: the buyer vault for USDG, else its token vault (the launchpad's, when there is one). */
|
|
23664
23829
|
vaultFor(token) {
|
|
23665
|
-
const t =
|
|
23830
|
+
const t = getAddress31(token);
|
|
23666
23831
|
if (t === this.config.deployment.token) return this.buyer;
|
|
23667
23832
|
if (this.launchpad !== null) return this.launchpad.tokenVault(t);
|
|
23668
23833
|
let v = this.#tokenVaults.get(t);
|
|
@@ -23701,7 +23866,7 @@ var init_agent = __esm({
|
|
|
23701
23866
|
if (text2 === void 0) return;
|
|
23702
23867
|
const r = JSON.parse(text2);
|
|
23703
23868
|
if (r.chainId !== this.config.chainId || typeof r.crank !== "string" || !isAddress13(r.crank, { strict: false })) throw new Error(`${SELLER_RECORD} is not a seller record of chain ${this.config.chainId}`);
|
|
23704
|
-
this.seller.setInitCrank(
|
|
23869
|
+
this.seller.setInitCrank(getAddress31(r.crank));
|
|
23705
23870
|
}
|
|
23706
23871
|
/** True once accept_payments set the seller vault up. */
|
|
23707
23872
|
async sellerReady() {
|
|
@@ -23721,7 +23886,7 @@ var init_agent = __esm({
|
|
|
23721
23886
|
let crank;
|
|
23722
23887
|
const known = await this.keys.folder.read(SELLER_RECORD);
|
|
23723
23888
|
if (known !== void 0) {
|
|
23724
|
-
crank =
|
|
23889
|
+
crank = getAddress31(JSON.parse(known).crank);
|
|
23725
23890
|
} else {
|
|
23726
23891
|
let res;
|
|
23727
23892
|
try {
|
|
@@ -23731,7 +23896,7 @@ var init_agent = __esm({
|
|
|
23731
23896
|
}
|
|
23732
23897
|
const body = await res.json().catch(() => null);
|
|
23733
23898
|
if (res.status !== 200 || typeof body?.crank !== "string" || !isAddress13(body.crank, { strict: false })) throw new Error(`the keeper answered ${res.status} without a crank`);
|
|
23734
|
-
crank =
|
|
23899
|
+
crank = getAddress31(body.crank);
|
|
23735
23900
|
this.seller.setInitCrank(crank);
|
|
23736
23901
|
await this.keys.folder.write(SELLER_RECORD, `${JSON.stringify({ chainId: this.config.chainId, token, crank, merchant })}
|
|
23737
23902
|
`);
|
|
@@ -23877,7 +24042,7 @@ async function loadConfig(env = process.env) {
|
|
|
23877
24042
|
keeperUrl: serviceUrl(env, "OSTRA_KEEPER_URL", services?.keeperUrl ?? null),
|
|
23878
24043
|
relayerUrl: serviceUrl(env, "OSTRA_RELAYER_URL", services?.relayerUrl ?? null),
|
|
23879
24044
|
aggregatorUrl: serviceUrl(env, "OSTRA_AGGREGATOR_URL", services?.aggregatorUrl ?? null),
|
|
23880
|
-
aiUrl: null
|
|
24045
|
+
aiUrl: serviceUrl(env, "OSTRA_AI_URL", services?.aiUrl ?? null)
|
|
23881
24046
|
};
|
|
23882
24047
|
}
|
|
23883
24048
|
var PROVER_WASM_FILES;
|
|
@@ -23895,8 +24060,21 @@ var init_config2 = __esm({
|
|
|
23895
24060
|
});
|
|
23896
24061
|
|
|
23897
24062
|
// src/tools.ts
|
|
23898
|
-
import { readFile as readFile6, stat as stat4 } from "node:fs/promises";
|
|
24063
|
+
import { readFile as readFile6, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
24064
|
+
import { join as join7 } from "node:path";
|
|
23899
24065
|
import { z } from "zod";
|
|
24066
|
+
function imageExt(b) {
|
|
24067
|
+
if (b.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) return "png";
|
|
24068
|
+
if (b[0] === 255 && b[1] === 216 && b[2] === 255) return "jpg";
|
|
24069
|
+
if (b.subarray(0, 4).toString("latin1") === "RIFF" && b.subarray(8, 12).toString("latin1") === "WEBP") return "webp";
|
|
24070
|
+
if (b.subarray(0, 4).toString("latin1") === "GIF8") return "gif";
|
|
24071
|
+
return "bin";
|
|
24072
|
+
}
|
|
24073
|
+
function videoExt(b) {
|
|
24074
|
+
if (b.subarray(4, 8).toString("latin1") === "ftyp") return "mp4";
|
|
24075
|
+
if (b.subarray(0, 4).equals(Buffer.from([26, 69, 223, 163]))) return "webm";
|
|
24076
|
+
return "bin";
|
|
24077
|
+
}
|
|
23900
24078
|
async function run2(fn, rpcUrls2) {
|
|
23901
24079
|
try {
|
|
23902
24080
|
return { content: [{ type: "text", text: toJson(await fn()) }] };
|
|
@@ -23947,6 +24125,60 @@ function registerTools(server, agent) {
|
|
|
23947
24125
|
{ url: z.string().url(), method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).default("GET"), headers: z.record(z.string(), z.string()).optional(), body: z.string().max(1e6).optional(), maxPrice: usdg, deposit: usdg.optional() },
|
|
23948
24126
|
(a) => agent.payments.pay({ url: a.url, method: a.method, maxPrice: a.maxPrice, ...a.headers === void 0 ? {} : { headers: a.headers }, ...a.body === void 0 ? {} : { body: a.body }, ...a.deposit === void 0 ? {} : { deposit: a.deposit } })
|
|
23949
24127
|
);
|
|
24128
|
+
const ai = () => {
|
|
24129
|
+
if (agent.ai === null) throw new Error("Ostra AI is not configured here (OSTRA_AI_URL)");
|
|
24130
|
+
return agent.ai;
|
|
24131
|
+
};
|
|
24132
|
+
const aiDir = join7(agent.config.home, AI_DIR);
|
|
24133
|
+
tool(
|
|
24134
|
+
"ostra_ai",
|
|
24135
|
+
"Runs an AI task on Ostra AI. text: request { messages, max_tokens, and optionally quality (best, balanced or cheapest; default best), privacy (no_training, zdr or standard; default no_training), temperature, top_p, seed, stop, tools, tool_choice, response_format, reasoning }. image: { prompt, and optionally n, quality, aspect_ratio, resolution, seed, background, output_format, image_quality, references }. video: { prompt, duration in seconds, and optionally quality, resolution (such as 480p; models priced per token need one), aspect_ratio, size, frame_images, references, generate_audio, seed }. A text task is read as a stream and answered whole, however long the model takes. No model is named: Ostra chooses one by its quality rating within maxPrice, and a task no model can do within it is refused with the reasons, nothing paid. Paid in USDG from the vault through an x402 channel to Ostra AI, opened when needed with `deposit` (default 1 USDG; its unused deposit comes back to the vault when the channel closes). maxPrice is the most the task may cost; what it did not cost stays as the vault's credit with Ostra AI and pays part of the next task (ostra_ai_credit). Images are saved as files in the agent's directory; a video task answers a job, followed with ostra_ai_job.",
|
|
24136
|
+
{ task: z.enum(AI_TASK_KINDS), request: z.record(z.string(), z.unknown()), maxPrice: usdg, deposit: usdg.optional() },
|
|
24137
|
+
async (a) => {
|
|
24138
|
+
const r = await ai().task(a.task, a.request, a.maxPrice, a.deposit);
|
|
24139
|
+
const answer = r.answer;
|
|
24140
|
+
if (a.task !== "image" || answer === null || typeof answer !== "object" || !Array.isArray(answer.images)) return r;
|
|
24141
|
+
await ensurePrivateDir(aiDir);
|
|
24142
|
+
const id = typeof answer.task === "string" && /^[0-9a-f]{1,64}$/.test(answer.task) ? answer.task : String(Date.now());
|
|
24143
|
+
const images = [];
|
|
24144
|
+
for (const [i, img] of answer.images.entries()) {
|
|
24145
|
+
if (typeof img.b64_json !== "string") {
|
|
24146
|
+
images.push({ media_type: img.media_type ?? null, file: null, note: "the answer carried no image data" });
|
|
24147
|
+
continue;
|
|
24148
|
+
}
|
|
24149
|
+
const bytes = Buffer.from(img.b64_json, "base64");
|
|
24150
|
+
const file = join7(aiDir, `${id}-${i}.${imageExt(bytes)}`);
|
|
24151
|
+
await writeFile3(file, bytes, { mode: 384 });
|
|
24152
|
+
images.push({ media_type: img.media_type, file, bytes: bytes.length });
|
|
24153
|
+
}
|
|
24154
|
+
return { ...r, answer: { ...answer, images } };
|
|
24155
|
+
}
|
|
24156
|
+
);
|
|
24157
|
+
tool(
|
|
24158
|
+
"ostra_ai_job",
|
|
24159
|
+
"A video job of ostra_ai: its status until it is final (completed, failed, cancelled or expired; the first final read settles its cost and credits the rest to the vault). With download (default true), a completed job's video is saved as a file in the agent's directory. Free: no payment.",
|
|
24160
|
+
{ job: z.string().regex(/^[0-9a-f]{32}$/, "the job ostra_ai answered: 32 hex characters"), download: z.boolean().default(true) },
|
|
24161
|
+
async (a) => {
|
|
24162
|
+
const s = await ai().job(a.job);
|
|
24163
|
+
const answer = s.answer;
|
|
24164
|
+
if (s.status !== 200 || answer === null || typeof answer !== "object") return s;
|
|
24165
|
+
const final = typeof answer.status === "string" && FINAL_JOB.includes(answer.status);
|
|
24166
|
+
if (!a.download || answer.status !== "completed") return { ...answer, final };
|
|
24167
|
+
const res = await fetch(ai().contentUrl(a.job), { signal: AbortSignal.timeout(6e5) });
|
|
24168
|
+
const size = Number(res.headers.get("content-length") ?? "0");
|
|
24169
|
+
if (!res.ok || size > MAX_VIDEO_BYTES) return { ...answer, final, file: null, note: `the video could not be read (${res.status}${size > MAX_VIDEO_BYTES ? `, ${size} bytes` : ""}); ask again` };
|
|
24170
|
+
const bytes = Buffer.from(await res.arrayBuffer());
|
|
24171
|
+
if (bytes.length > MAX_VIDEO_BYTES) return { ...answer, final, file: null, note: `the video is larger than ${MAX_VIDEO_BYTES} bytes` };
|
|
24172
|
+
await ensurePrivateDir(aiDir);
|
|
24173
|
+
const file = join7(aiDir, `${a.job}.${videoExt(bytes)}`);
|
|
24174
|
+
await writeFile3(file, bytes, { mode: 384 });
|
|
24175
|
+
return { ...answer, final, file, bytes: bytes.length };
|
|
24176
|
+
}
|
|
24177
|
+
);
|
|
24178
|
+
tool("ostra_ai_credit", "The vault's credit with Ostra AI: what earlier tasks were paid and did not cost, used first by the next task (USDG).", {}, async () => {
|
|
24179
|
+
const c = await ai().credit();
|
|
24180
|
+
return { payer: c.payer, credit: typeof c.credit === "string" && /^[0-9]+$/.test(c.credit) ? formatTokenAmount(BigInt(c.credit)) : c.credit };
|
|
24181
|
+
});
|
|
23950
24182
|
tool("accept_payments", "Sets up the seller side: the seller vault with the Ostra keeper's crank (it claims vouchers), and the merchant key for the seller server (merchant/).", {}, () => agent.acceptPayments());
|
|
23951
24183
|
tool("seller_balance", "The seller vault: balance, nonce, crank.", {}, async () => {
|
|
23952
24184
|
if (!await agent.sellerReady()) throw new Error("this agent has no seller vault yet; call accept_payments first");
|
|
@@ -24060,7 +24292,7 @@ function registerTools(server, agent) {
|
|
|
24060
24292
|
);
|
|
24061
24293
|
tool(
|
|
24062
24294
|
"launch",
|
|
24063
|
-
"Launches a token on the Ostra launchpad (1 billion supply) paired with USDG (default), ETH, OSTRA or a listed stock token (pairs), from the agent's creator vault of that pair, optionally with a dev buy in the pair's token paid by that creator vault in the same transaction and vesting to the agent's token vault. The market cap is in US dollars, set in the pair's token at its price now (Chainlink for ETH and stocks; OSTRA at Chainlink ETH/USD times its
|
|
24295
|
+
"Launches a token on the Ostra launchpad (1 billion supply) paired with USDG (default), ETH, OSTRA or a listed stock token (pairs), from the agent's creator vault of that pair, optionally with a dev buy in the pair's token paid by that creator vault in the same transaction and vesting to the agent's token vault. The market cap is in US dollars, set in the pair's token at its price now (Chainlink for ETH and stocks; OSTRA at Chainlink ETH/USD times its price in the pool it graduated to). The relayer fronts the 0.0002 ETH launch fee and charges it in USDG. The launch is simulated first; nothing is signed if it would fail. `options` sets LaunchParams fields (taxes, buckets, anti-snipe, limits, graduation, circuit breaker) beyond Ostra's defaults.",
|
|
24064
24296
|
{
|
|
24065
24297
|
name: z.string().min(1).max(64),
|
|
24066
24298
|
symbol: z.string().regex(/^[A-Za-z0-9]{1,11}$/),
|
|
@@ -24172,13 +24404,14 @@ function launchOptions(raw) {
|
|
|
24172
24404
|
}
|
|
24173
24405
|
return out;
|
|
24174
24406
|
}
|
|
24175
|
-
var toJson, address5, usdg, units, pair2, slippage2, bytes323, swapToken, tokenAddress, uri, publicFields, BIGINT_FIELDS, ALLOWED_OPTIONS;
|
|
24407
|
+
var toJson, address5, usdg, units, pair2, slippage2, bytes323, swapToken, tokenAddress, uri, publicFields, AI_DIR, MAX_VIDEO_BYTES, FINAL_JOB, BIGINT_FIELDS, ALLOWED_OPTIONS;
|
|
24176
24408
|
var init_tools = __esm({
|
|
24177
24409
|
"src/tools.ts"() {
|
|
24178
24410
|
"use strict";
|
|
24179
24411
|
init_define_OSTRA_PACKAGED();
|
|
24180
24412
|
init_src3();
|
|
24181
24413
|
init_src();
|
|
24414
|
+
init_disk();
|
|
24182
24415
|
toJson = (value) => JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v, 2);
|
|
24183
24416
|
address5 = z.string().regex(/^0x[0-9a-fA-F]{40}$/, "an address: 0x and 40 hex characters");
|
|
24184
24417
|
usdg = z.string().regex(/^(0|[1-9][0-9]*)(\.[0-9]{1,6})?$/, "a USDG amount: a plain decimal with at most 6 decimals");
|
|
@@ -24203,6 +24436,9 @@ var init_tools = __esm({
|
|
|
24203
24436
|
x: z.string().url().max(200).optional().describe("the X (Twitter) profile link"),
|
|
24204
24437
|
telegram: z.string().url().max(200).optional()
|
|
24205
24438
|
};
|
|
24439
|
+
AI_DIR = "ai";
|
|
24440
|
+
MAX_VIDEO_BYTES = 512 * 1024 * 1024;
|
|
24441
|
+
FINAL_JOB = ["completed", "failed", "cancelled", "expired"];
|
|
24206
24442
|
BIGINT_FIELDS = /* @__PURE__ */ new Set(["minDividendBalance", "maxBuy", "maxWallet", "graduationThreshold"]);
|
|
24207
24443
|
ALLOWED_OPTIONS = /* @__PURE__ */ new Set([
|
|
24208
24444
|
"tiers",
|