@ostraagent/mcp 0.1.11 → 0.1.12
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 +4 -3
- package/dist/ostra-mcp.js +485 -111
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,16 +47,16 @@ Keep the file and the passphrase off the machine. On a new machine, run `npx -y
|
|
|
47
47
|
- **Selling services:** `accept_payments`, `seller_balance`, `seller_withdraw`
|
|
48
48
|
- **Recovery:** `recovery_status`, `set_guardian`, `set_recovery_policy`, `cancel_recovery`, `support_recovery`, `request_recovery`
|
|
49
49
|
- **Withdrawal lock:** `vault_lock` (status; set a withdrawal address on another device, a delay of 36 hours to 14 days and a daily limit: anything else the vault sends counts against the limit, and every loosening waits the delay; off; cancel what waits), `vault_link` (the linked vault a Borro loan is paid to), `vault_approve_hash` (EIP-1271 approvals; under the lock they wait the delay), `guard_vault` (as a guardian of another locked vault: cancel its waiting changes, revoke an approval, sweep it to its withdrawal address, bring its Borro shares or collateral back)
|
|
50
|
-
- **Strategies:** `strategy_plan` (a conservative plan, USDG into a cash vault that passes every check, and, when the agent holds SPY, QQQ or NVDA, a balanced one: the stock as collateral on Borro, USDG borrowed into the cash vault; each with its steps, gas, 30-day earnings net of gas, risks and when it stops; every step earns over 3x its gas in 30 days or is left out), `strategy_apply` (runs a plan step by step, each checked and sized again right before it is signed), `strategy_check` (each run's check of the cash vaults and the carries; urgent exits and repayments run at once), `strategy_report` (what the strategies earn). Only for an agent registered in ERC-8004 (`
|
|
50
|
+
- **Strategies:** `strategy_plan` (a conservative plan, USDG into a cash vault that passes every check, and, when the agent holds SPY, QQQ or NVDA, a balanced one: the stock as collateral on Borro, USDG borrowed into the cash vault; each with its steps, gas, 30-day earnings net of gas, risks and when it stops; every step earns over 3x its gas in 30 days or is left out), `strategy_apply` (runs a plan step by step, each checked and sized again right before it is signed), `strategy_check` (each run's check of the cash vaults and the carries; urgent exits and repayments run at once), `strategy_report` (what the strategies earn). Only for an agent registered in ERC-8004 (`publish_profile`); `strategy_check` and its exits run for every vault
|
|
51
51
|
- **Trading capital:** `trading` (USDG set aside for the agent's own trades, with Ostra's limits, which an agent may only tighten: a position at most 25% of the capital and no larger than a buy that moves the price 1%; buys stop for the day after a 5% loss that day and for the week after 10% that week)
|
|
52
52
|
- **OstraBreaker:** `breaker` (status, or arm: OstraBreaker as a guardian of the USDG vault, watching each cash vault; when a limit is crossed on chain, Ostra's breaker keeper sends the trip and the position comes back to the vault). `vault_lock set` arms it first by itself
|
|
53
53
|
- **Raeto:** `raeto` (400+ AI models through one OpenAI-compatible API, paid in credits of the vault's own Raeto account: login with EIP-1271, credits, models, fund in USDG from the vault, fund from what the cash vault earned, completions; images are saved as files)
|
|
54
54
|
- **Borro:** `borro_markets`, `borro_position`, `borro_lend` (USDG, or a stock from the agent's vault of it, into Borro's Morpho vault of it), `borro_withdraw`, `borro_collateral`, `borro_borrow` (USDG against the stock vault's collateral, into the vault; the vault caps a loan at half of what the market's LLTV allows), `borro_repay`
|
|
55
55
|
- **Ostrapad:** `pad_publish` (lists offers in the agent's ERC-8004 registration file, paid into its USDG vault; unpublish, status, a voluntary provider bond), `pad_search` (Ostra's index of listed agents, or one agent's listing read from the chain), `pad_order` (orders an offer: the order pinned to IPFS, the budget sent to the job's escrow box and the job created; cancel; appeal a pool decision), `pad_jobs` (the agent's jobs as client, provider or evaluator, with their order and delivery files; accept; claim), `pad_deliver` (the delivery pinned and submitted), `pad_evaluate` (decide a job the agent judges, vote on an appeal panel, the evaluator pool), `pad_earnings`. A job's budget is paid to the provider less 0.5% once its evaluator's approval stands (a pool decision after its 48-hour appeal window), and refunded to the client when rejected or expired; order, delivery and decision files are public JSON on IPFS, checked against their sha256 on chain
|
|
56
56
|
- **Launchpad (closed):** the launchpad takes no new launches or buys; its exits remain: `sell`, `token_vault`, `transfer_token`, `claim_dividends`, `release_creator_payout`, `airdrop_claim`, `airdrop_close`, `vesting_info`, `vesting_release`, `vesting_claim_dividends`
|
|
57
|
-
- **Ostra Swap:** `ostra_swap_quote`, `ostra_swap` (between the agent's vaults of USDG, WETH, $OSTRA, listed stock tokens and launched tokens, routed through Uniswap v3 and v4; tokens by address or symbol; a swap that moves the price more than `maxImpactBps`, 1% by default, is split into up to 16 parts 60 seconds apart, each its own signed swap quoted again right before it is signed), `ostra_swap_split` (the split swaps: their parts, run the parts due, cancel one)
|
|
57
|
+
- **Ostra Swap:** `ostra_swap_quote`, `ostra_swap` (between the agent's vaults of USDG, WETH, $OSTRA, listed stock tokens and launched tokens, routed through Uniswap v3 and v4; tokens by address or symbol; a swap that moves the price more than `maxImpactBps`, 1% by default, is split into up to 16 parts 60 seconds apart, each its own signed swap quoted again right before it is signed; a swap not done within `OSTRA_SWAP_ANSWER_MS` answers `pending` and goes on), `ostra_swap_split` (the split swaps: their parts, run the parts due, cancel one), `ostra_swap_orders` (swaps still running, orders not finished, and the last finished ones with what they paid)
|
|
58
58
|
- **Privacy:** `private_shield` (from a vault into a private note), `private_balance`, `private_swap`, `private_unshield` (to an address, or with `toPrivateVault` to a new private vault of the agent), `private_withdraw` (from a private vault), `private_recover` (finds the notes and private vaults again from the seed alone), `auto_shield` (everything the creator vault holds beyond what it keeps, into private notes). Notes are spent with a zero-knowledge proof made on the agent's machine by the WebAssembly prover the package carries. A spend does not show which note it spends; the token, the amounts, the times, the vault a shield comes from and an unshield's recipient are public, so a private vault's first balance matches the unshield that paid it
|
|
59
|
-
- **Identity:** `profile`, `
|
|
59
|
+
- **Identity:** `profile`, `publish_profile` (no inputs: registers the agent in ERC-8004 when it is not yet, and publishes the same profile for every Ostra agent, "Ostra Agent #id" with Ostra's agent card as its image; an Ostrapad listing in the registration file is kept), `upload_image` (files of Ostrapad orders and deliveries)
|
|
60
60
|
|
|
61
61
|
Every spend is simulated before its one-time key signs it. When a tool refuses, the error says whether it refused before anything was signed.
|
|
62
62
|
|
|
@@ -84,6 +84,7 @@ All settings are optional.
|
|
|
84
84
|
| `OSTRA_ETH_RPC_URL` | `https://ethereum-rpc.publicnode.com` | An Ethereum mainnet RPC, for Chainlink's USDe / USD feed the strategies read before lending to a cash vault that can lend against USDe. `off`: no cash goes into such a vault. Never printed |
|
|
85
85
|
| `OSTRA_RAETO_URL` | `https://api.raeto.cc` | Raeto's API. `off` turns the `raeto` tool off |
|
|
86
86
|
| `OSTRA_PAD_INDEXER_URL` | `https://app.ostraagent.xyz` | Ostra's Ostrapad index, for `pad_search` by words. `off` turns that search off (a listing by agent id is still read from the chain) |
|
|
87
|
+
| `OSTRA_SWAP_ANSWER_MS` | `40000` | How long `ostra_swap` and `trading` buy and sell wait for their swap before answering `pending` while it goes on (milliseconds, 1 to 600000), within the 60 s many MCP clients wait for a call |
|
|
87
88
|
| `OSTRA_IPFS_GATEWAYS` | The Ostra uploader (`https://relayer.ostraagent.xyz/v1/ipfs/`), then Pinata's gateway, then ipfs.io | The IPFS gateways profiles and Ostrapad's files are read through, comma-separated, in the order they are tried (each URL ending in `/`). A raw CID is checked against the bytes, whichever gateway answers |
|
|
88
89
|
| `OSTRA_DEPLOYMENT` | Ostra on Robinhood Chain mainnet | Path of another deployment record (JSON). With it, the four services default to off |
|
|
89
90
|
|
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.12", deployment: { version: 1, chainId: 4663, fromBlock: "91991509", token: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", batchSettlement: "0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003", vaultImplementation: "0xec0ca4A1393D91c42cA809F7F9dd82Bd597E8E58", vaultBeacon: "0xE9F525B9EaeE48d13AEd28fE146F48f2832a18a0", vaultFactory: "0x043a15c514CFE2c797d33520bFF91a5DCdbf2979", poolImplementation: "0xC04d4a222dC1C966640B977608bE29949b0648ec", poolBeacon: "0x30669Ca534921038a531BBE27116d85bB7406fFF", pool: "0x6ea80F2462e5Fd783B0Ec3B2c7BaC96795980CD6", splitFactory: "0xAAf54A483B2c7c2c5ecFc1eDED5ed1619C1bA882", beaconOwner: "0x55533a51d9bd9b06F2D179d919BB31995EF96E5e", registry: "0xcE6Cc1f93744f4090DA1444Bb8590d9206157506", vaultModule: "0x55A89fF907f5F5756470e2ec5Dc5E4E1C54Da770", launchpad: { hook: "0x63A784afb8905452aDceC471a45E555F5caE68cC", fees: "0x8e79671DC9729476614C78aFcf2345D4c1963801", launchpad: "0xfC57162C0e3f9773F97fEa8d276e957d7c43A6C5", creatorSplit: "0x987994dE6A1d5303B9e3F50977cB0321BA4D033B", dispatcher: "0x44Bb65164b2855f8E80B142d5Fb9bDb72E869986", locker: "0xb593812363bAd70Ee381c7B54c4FC82b0BA3A4A7", devBuy: "0x0e1Fd799E136dcfEcad5695B07Ac5DAc5B2fF4bc", vesting: "0xadD9C1995910457312c156E7D8120D1b447E179a", airdrop: "0xBC798D956aF4c2B104FFC6106d5322294Bc103bb", owner: "0x6569E27A95a6A3E92A311B4Cc6600fed56aA50A2" }, breaker: "0x2E33244dE6A64007204f763e9ef81FC33F1a8e01" }, 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
|
|
|
@@ -13581,6 +13581,14 @@ var init_abi = __esm({
|
|
|
13581
13581
|
}
|
|
13582
13582
|
});
|
|
13583
13583
|
|
|
13584
|
+
// ../sdk/src/agent-card.ts
|
|
13585
|
+
var init_agent_card = __esm({
|
|
13586
|
+
"../sdk/src/agent-card.ts"() {
|
|
13587
|
+
"use strict";
|
|
13588
|
+
init_define_OSTRA_PACKAGED();
|
|
13589
|
+
}
|
|
13590
|
+
});
|
|
13591
|
+
|
|
13584
13592
|
// ../sdk/src/hash.ts
|
|
13585
13593
|
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
13586
13594
|
import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
|
|
@@ -15652,21 +15660,54 @@ var init_breaker = __esm({
|
|
|
15652
15660
|
|
|
15653
15661
|
// ../sdk/src/chain.ts
|
|
15654
15662
|
import { BaseError as BaseError2, createPublicClient, defineChain, http } from "viem";
|
|
15655
|
-
function
|
|
15656
|
-
const
|
|
15657
|
-
|
|
15663
|
+
function laggingRead(e) {
|
|
15664
|
+
const lag = (x) => {
|
|
15665
|
+
const o = x;
|
|
15666
|
+
if (o.code === -32602) return true;
|
|
15667
|
+
return o.code === -32e3 && /unsupported block number/i.test(`${String(o.details ?? "")} ${String(o.message ?? "")}`);
|
|
15668
|
+
};
|
|
15669
|
+
return e instanceof BaseError2 ? e.walk(lag) !== null : lag(e);
|
|
15670
|
+
}
|
|
15671
|
+
function transient(e) {
|
|
15672
|
+
const o = e;
|
|
15673
|
+
if (o === null || typeof o !== "object") return true;
|
|
15674
|
+
if (o.name === "AbortError") return false;
|
|
15675
|
+
if (typeof o.code === "number") return [-1, -32005, -32603, 429, -32007].includes(o.code);
|
|
15676
|
+
if (typeof o.status === "number" && o.status !== 0) return [403, 408, 413, 429, 500, 502, 503, 504].includes(o.status);
|
|
15677
|
+
return true;
|
|
15658
15678
|
}
|
|
15659
|
-
function
|
|
15660
|
-
const
|
|
15679
|
+
function failureText(e, url) {
|
|
15680
|
+
const o = e;
|
|
15681
|
+
const parts = [o?.shortMessage ?? o?.name ?? String(e)];
|
|
15682
|
+
if (typeof o?.code === "number") parts.push(`code ${o.code}`);
|
|
15683
|
+
if (typeof o?.status === "number" && o.status !== 0) parts.push(`HTTP ${o.status}`);
|
|
15684
|
+
if (typeof o?.details === "string" && o.details !== "" && o.details !== parts[0]) parts.push(o.details);
|
|
15685
|
+
return redact(parts.join("; "), url).slice(0, 300);
|
|
15686
|
+
}
|
|
15687
|
+
function retryingHttp(url, o) {
|
|
15688
|
+
const own = o !== void 0;
|
|
15689
|
+
const base = own ? http(url, { retryCount: 0, timeout: o.timeoutMs ?? RPC_TIMEOUT_MS }) : http(url, { retryCount: RPC_RETRIES, retryDelay: RPC_RETRY_WAIT_MS, timeout: RPC_TIMEOUT_MS });
|
|
15690
|
+
const retries = o?.retryCount ?? RPC_RETRIES;
|
|
15661
15691
|
return ((params) => {
|
|
15662
15692
|
const t = base(params);
|
|
15663
15693
|
const request = (async (args, options) => {
|
|
15664
|
-
|
|
15694
|
+
let lagging = 0;
|
|
15695
|
+
let failed = 0;
|
|
15696
|
+
for (; ; ) {
|
|
15665
15697
|
try {
|
|
15666
15698
|
return await t.request(args, options);
|
|
15667
15699
|
} catch (e) {
|
|
15668
|
-
|
|
15669
|
-
|
|
15700
|
+
let wait;
|
|
15701
|
+
if (lagging < INVALID_PARAMS_RETRIES && IDEMPOTENT_READS.has(args.method) && laggingRead(e)) {
|
|
15702
|
+
wait = INVALID_PARAMS_WAIT_MS * 2 ** lagging;
|
|
15703
|
+
lagging++;
|
|
15704
|
+
} else if (own && failed < retries && transient(e)) {
|
|
15705
|
+
const after = e.headers?.get?.("Retry-After");
|
|
15706
|
+
wait = after !== null && after !== void 0 && /^[0-9]+$/.test(after) ? Math.min(Number(after) * 1e3, RETRY_AFTER_MAX_MS) : RPC_RETRY_WAIT_MS * 2 ** failed;
|
|
15707
|
+
failed++;
|
|
15708
|
+
} else throw e;
|
|
15709
|
+
o?.onRetry?.({ method: args.method, retry: lagging + failed, waitMs: wait, error: failureText(e, url) });
|
|
15710
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
15670
15711
|
}
|
|
15671
15712
|
}
|
|
15672
15713
|
});
|
|
@@ -15683,7 +15724,7 @@ async function assertRobinhoodChain(client) {
|
|
|
15683
15724
|
function redact(text3, secret2) {
|
|
15684
15725
|
return secret2 === "" ? text3 : text3.split(secret2).join("<rpc>");
|
|
15685
15726
|
}
|
|
15686
|
-
var robinhoodChain, IDEMPOTENT_READS, INVALID_PARAMS_RETRIES, INVALID_PARAMS_WAIT_MS;
|
|
15727
|
+
var robinhoodChain, IDEMPOTENT_READS, INVALID_PARAMS_RETRIES, INVALID_PARAMS_WAIT_MS, RPC_RETRIES, RPC_RETRY_WAIT_MS, RPC_TIMEOUT_MS, RETRY_AFTER_MAX_MS;
|
|
15687
15728
|
var init_chain = __esm({
|
|
15688
15729
|
"../sdk/src/chain.ts"() {
|
|
15689
15730
|
"use strict";
|
|
@@ -15700,6 +15741,10 @@ var init_chain = __esm({
|
|
|
15700
15741
|
IDEMPOTENT_READS = /* @__PURE__ */ new Set(["eth_call", "eth_getCode", "eth_getStorageAt", "eth_getBalance", "eth_getBlockByNumber", "eth_getBlockByHash", "eth_blockNumber", "eth_chainId", "eth_getTransactionReceipt", "eth_getTransactionByHash", "eth_getTransactionCount", "eth_gasPrice"]);
|
|
15701
15742
|
INVALID_PARAMS_RETRIES = 4;
|
|
15702
15743
|
INVALID_PARAMS_WAIT_MS = 1e3;
|
|
15744
|
+
RPC_RETRIES = 8;
|
|
15745
|
+
RPC_RETRY_WAIT_MS = 1e3;
|
|
15746
|
+
RPC_TIMEOUT_MS = 3e4;
|
|
15747
|
+
RETRY_AFTER_MAX_MS = 1e4;
|
|
15703
15748
|
}
|
|
15704
15749
|
});
|
|
15705
15750
|
|
|
@@ -19873,6 +19918,7 @@ var init_browser = __esm({
|
|
|
19873
19918
|
"use strict";
|
|
19874
19919
|
init_define_OSTRA_PACKAGED();
|
|
19875
19920
|
init_abi();
|
|
19921
|
+
init_agent_card();
|
|
19876
19922
|
init_aggregator();
|
|
19877
19923
|
init_airdrop();
|
|
19878
19924
|
init_backup();
|
|
@@ -20406,9 +20452,11 @@ var init_relay = __esm({
|
|
|
20406
20452
|
}
|
|
20407
20453
|
};
|
|
20408
20454
|
PendingSpendUnpaidError = class extends Error {
|
|
20409
|
-
|
|
20455
|
+
onCredit;
|
|
20456
|
+
constructor(message, onCredit) {
|
|
20410
20457
|
super(message);
|
|
20411
20458
|
this.name = "PendingSpendUnpaidError";
|
|
20459
|
+
this.onCredit = onCredit;
|
|
20412
20460
|
}
|
|
20413
20461
|
};
|
|
20414
20462
|
RelayerError = class extends Error {
|
|
@@ -20705,6 +20753,7 @@ var init_relay = __esm({
|
|
|
20705
20753
|
async #post(calls, extra, headers = {}) {
|
|
20706
20754
|
const body2 = { calls: calls.map((c) => ({ to: getAddress17(c.to), data: c.data })) };
|
|
20707
20755
|
if (extra.prepay === true) body2.prepay = true;
|
|
20756
|
+
if (extra.onCredit === true) body2.onCredit = true;
|
|
20708
20757
|
if (extra.payer !== null) body2.payer = extra.payer;
|
|
20709
20758
|
if (extra.allowFailedSwaps === true) body2.allowFailedSwaps = true;
|
|
20710
20759
|
return this.#http("POST", "/v1/relay", JSON.stringify(body2), headers);
|
|
@@ -20899,9 +20948,11 @@ var init_relay = __esm({
|
|
|
20899
20948
|
}
|
|
20900
20949
|
async send(calls, options = {}) {
|
|
20901
20950
|
await this.facts();
|
|
20951
|
+
const credit = options.onCredit === true;
|
|
20952
|
+
const post2 = async () => this.#post(calls, { prepay: options.prepay === true, payer: credit ? null : await this.#payer(), allowFailedSwaps: options.allowFailedSwaps === true, onCredit: credit });
|
|
20902
20953
|
let notSent = "";
|
|
20903
20954
|
for (let resend = 0; resend < MAX_RESENDS; resend++) {
|
|
20904
|
-
let answer = await
|
|
20955
|
+
let answer = await post2();
|
|
20905
20956
|
let again = false;
|
|
20906
20957
|
for (let step2 = 0; step2 < MAX_STEPS && !again; step2++) {
|
|
20907
20958
|
const b = answer.body;
|
|
@@ -20911,14 +20962,15 @@ var init_relay = __esm({
|
|
|
20911
20962
|
await this.#landed(hash);
|
|
20912
20963
|
return hash;
|
|
20913
20964
|
}
|
|
20965
|
+
if (answer.status === 402 && credit) throw new RelayerError(402, "no_credit", "the relayer does not send this spend on credit (it asks for payment); nothing was sent");
|
|
20914
20966
|
if (answer.status === 402) {
|
|
20915
20967
|
answer = await this.#pay(calls, answer, options);
|
|
20916
20968
|
continue;
|
|
20917
20969
|
}
|
|
20918
20970
|
if (answer.status === 403 && (error === "vault_in_debt" || error === "open_unpaid")) {
|
|
20919
|
-
if (options.reservation !== void 0 && options.reservation !== null) throw new RelayerError(403, error, String(b?.message ?? error));
|
|
20971
|
+
if (credit || options.reservation !== void 0 && options.reservation !== null) throw new RelayerError(403, error, String(b?.message ?? error));
|
|
20920
20972
|
await this.#ensureChannel(1n, options.openChannel, null);
|
|
20921
|
-
answer = await
|
|
20973
|
+
answer = await post2();
|
|
20922
20974
|
continue;
|
|
20923
20975
|
}
|
|
20924
20976
|
if (answer.status === 409 && error === "not_sent") {
|
|
@@ -21463,10 +21515,14 @@ var init_vault = __esm({
|
|
|
21463
21515
|
* Runs `fn` with what a vault spend needs to be paid. With the relayer: a
|
|
21464
21516
|
* reservation of unused relayer channel deposit for its price (a channel is
|
|
21465
21517
|
* opened first if none has room), released once `fn` is done. When a spend
|
|
21466
|
-
* signed earlier waits and no relayer channel can pay for it
|
|
21467
|
-
*
|
|
21468
|
-
*
|
|
21469
|
-
*
|
|
21518
|
+
* signed earlier waits and no relayer channel can pay for it (its key is
|
|
21519
|
+
* the one a new channel's open needs), the relayer is asked to send it on
|
|
21520
|
+
* credit, as the vault's debt, and the channel opened next pays that debt
|
|
21521
|
+
* with its first voucher; `fn` then runs as usual and its result names what
|
|
21522
|
+
* was sent first (`sentFirst`). Only when the relayer does not send it so,
|
|
21523
|
+
* the local fee payer sends it if it holds the ETH. `moves` is what the
|
|
21524
|
+
* spend takes out of this vault: a relayer channel opened from the buyer
|
|
21525
|
+
* vault for it leaves that much in the buyer vault.
|
|
21470
21526
|
*/
|
|
21471
21527
|
async #paidSpend(sender, fn, moves = 0n, gas = VAULT_SPEND_GAS, extraWei = 0n) {
|
|
21472
21528
|
await this.#finishRecoveryFirst(sender);
|
|
@@ -21478,10 +21534,30 @@ var init_vault = __esm({
|
|
|
21478
21534
|
reservation = await sender.reserve(gas, sender === this.#sender ? this.#opener() : void 0, this.#paysRelayer() ? moves : 0n, extraWei);
|
|
21479
21535
|
} catch (err) {
|
|
21480
21536
|
if (!(err instanceof PendingSpendUnpaidError)) throw err;
|
|
21537
|
+
let refused = "";
|
|
21538
|
+
const credit = err.onCredit;
|
|
21539
|
+
if (sender.relayed && credit !== void 0) {
|
|
21540
|
+
let sentFirst = null;
|
|
21541
|
+
try {
|
|
21542
|
+
sentFirst = await (credit.owner === this ? credit.unqueued() : credit.queued());
|
|
21543
|
+
} catch (e) {
|
|
21544
|
+
if (!(e instanceof RelayerError)) throw e;
|
|
21545
|
+
refused = `; the relayer did not send it on credit (${e.message})`;
|
|
21546
|
+
}
|
|
21547
|
+
if (refused === "") {
|
|
21548
|
+
const again = await sender.reserve(gas, sender === this.#sender ? this.#opener() : void 0, this.#paysRelayer() ? moves : 0n, extraWei);
|
|
21549
|
+
try {
|
|
21550
|
+
const r = await fn(sender, again);
|
|
21551
|
+
return sentFirst !== null && r !== null && typeof r === "object" ? { ...r, sentFirst } : r;
|
|
21552
|
+
} finally {
|
|
21553
|
+
sender.release(again);
|
|
21554
|
+
}
|
|
21555
|
+
}
|
|
21556
|
+
}
|
|
21481
21557
|
const local = new LocalSender(this.#client, this.#transport, this.#keys.feePayer, this.#keys.escrow);
|
|
21482
21558
|
const need = gas * await this.#client.getGasPrice() * ETH_HEADROOM + extraWei;
|
|
21483
21559
|
if (await ethBalance(this.#client, this.#keys.feePayer.address) < need) {
|
|
21484
|
-
throw new Error(`${err.message}; send at least ${formatEth(need)} ETH to the fee payer ${this.#keys.feePayer.address} and call again: it sends that operation itself`);
|
|
21560
|
+
throw new Error(`${err.message}${refused}; send at least ${formatEth(need)} ETH to the fee payer ${this.#keys.feePayer.address} and call again: it sends that operation itself`);
|
|
21485
21561
|
}
|
|
21486
21562
|
return fn(local, null);
|
|
21487
21563
|
}
|
|
@@ -21491,6 +21567,25 @@ var init_vault = __esm({
|
|
|
21491
21567
|
sender.release(reservation);
|
|
21492
21568
|
}
|
|
21493
21569
|
}
|
|
21570
|
+
/**
|
|
21571
|
+
* Sends the spend signed earlier through the relayer on credit (SendOptions.onCredit): the vault owes its price, which
|
|
21572
|
+
* the first voucher of the channel opened next pays. Returns what was sent, or null when nothing waits any more.
|
|
21573
|
+
*/
|
|
21574
|
+
async #sendPendingOnCredit() {
|
|
21575
|
+
const sender = this.#sender;
|
|
21576
|
+
if (!sender.relayed) return null;
|
|
21577
|
+
const vault = await this.vaultAddress();
|
|
21578
|
+
const v = await this.#read(vault);
|
|
21579
|
+
if (v === null) return null;
|
|
21580
|
+
const credit = {
|
|
21581
|
+
relayed: true,
|
|
21582
|
+
payer: () => sender.payer(),
|
|
21583
|
+
send: (calls, o = {}) => sender.send(calls, { ...o, reservation: null, onCredit: true }),
|
|
21584
|
+
reserve: async () => null,
|
|
21585
|
+
release: () => void 0
|
|
21586
|
+
};
|
|
21587
|
+
return this.#sendPending(vault, v, credit, null);
|
|
21588
|
+
}
|
|
21494
21589
|
/**
|
|
21495
21590
|
* Version 3 vaults: the spend is run first with a throwaway key (sdk simulateVaultSpend) and refused before it is
|
|
21496
21591
|
* signed when it would revert, or land as a failure (a SupportRecovery the other vault refuses). A signed spend that
|
|
@@ -21720,7 +21815,11 @@ the signed channel open is kept; the next open_channel or withdraw call sends it
|
|
|
21720
21815
|
const v = await this.#read(vault);
|
|
21721
21816
|
if (v === null) throw new Error(this.#missing());
|
|
21722
21817
|
if (await this.#pending(v) !== null) {
|
|
21723
|
-
throw new PendingSpendUnpaidError("a vault operation signed earlier waits to be sent and no channel to the relayer has deposit left to pay for it"
|
|
21818
|
+
throw new PendingSpendUnpaidError("a vault operation signed earlier waits to be sent and no channel to the relayer has deposit left to pay for it", {
|
|
21819
|
+
owner: this,
|
|
21820
|
+
queued: () => this.#serial(() => this.#sendPendingOnCredit()),
|
|
21821
|
+
unqueued: () => this.#sendPendingOnCredit()
|
|
21822
|
+
});
|
|
21724
21823
|
}
|
|
21725
21824
|
await this.#notFrozen(vault, "the vault");
|
|
21726
21825
|
const balance = await this.#balance(vault);
|
|
@@ -23548,24 +23647,17 @@ function imageUri(value) {
|
|
|
23548
23647
|
return value;
|
|
23549
23648
|
}
|
|
23550
23649
|
function profileFile(p) {
|
|
23551
|
-
const
|
|
23552
|
-
|
|
23553
|
-
const x = link2(p.x, "x");
|
|
23554
|
-
const telegram = link2(p.telegram, "telegram");
|
|
23555
|
-
if (website !== void 0) services.push({ name: "web", endpoint: website });
|
|
23556
|
-
if (x !== void 0) services.push({ name: "X", endpoint: x });
|
|
23557
|
-
if (telegram !== void 0) services.push({ name: "Telegram", endpoint: telegram });
|
|
23558
|
-
services.push({ name: "agentWallet", endpoint: `eip155:${ROBINHOOD_CHAIN_ID}:${p.vault}` });
|
|
23650
|
+
const id = p.agentId === void 0 || p.agentId === null ? null : p.agentId;
|
|
23651
|
+
if (id !== null && !/^(0|[1-9][0-9]{0,29})$/.test(id)) throw new RangeError("an agent id is a decimal number");
|
|
23559
23652
|
const image = imageUri(p.image);
|
|
23560
|
-
const description = text2(p.description, "description", 1e3);
|
|
23561
23653
|
return {
|
|
23562
23654
|
type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
|
|
23563
|
-
name:
|
|
23564
|
-
|
|
23655
|
+
name: id === null ? AGENT_NAME : `${AGENT_NAME} #${id}`,
|
|
23656
|
+
description: AGENT_DESCRIPTION,
|
|
23565
23657
|
...image === void 0 ? {} : { image },
|
|
23566
|
-
services,
|
|
23658
|
+
services: [{ name: "agentWallet", endpoint: `eip155:${ROBINHOOD_CHAIN_ID}:${p.vault}` }],
|
|
23567
23659
|
active: true,
|
|
23568
|
-
registrations:
|
|
23660
|
+
registrations: id === null ? [] : [{ agentId: Number(id), agentRegistry: `eip155:${ROBINHOOD_CHAIN_ID}:${ERC8004_IDENTITY_REGISTRY}` }]
|
|
23569
23661
|
};
|
|
23570
23662
|
}
|
|
23571
23663
|
function tokenMetadataFile(m) {
|
|
@@ -23604,6 +23696,9 @@ function uploaderUrl(relayerUrl) {
|
|
|
23604
23696
|
function uploadJson(relayerUrl, value) {
|
|
23605
23697
|
return post(`${uploaderUrl(relayerUrl)}/json`, JSON.stringify(value), "application/json");
|
|
23606
23698
|
}
|
|
23699
|
+
function agentCardUri(relayerUrl, agentId) {
|
|
23700
|
+
return post(`${uploaderUrl(relayerUrl)}/agent-card`, JSON.stringify({ agentId }), "application/json");
|
|
23701
|
+
}
|
|
23607
23702
|
function uploadImage(relayerUrl, bytes) {
|
|
23608
23703
|
const base = uploaderUrl(relayerUrl);
|
|
23609
23704
|
if (bytes.length === 0 || bytes.length > MAX_UPLOAD_IMAGE_BYTES) throw new RangeError(`the image must be 1 to ${MAX_UPLOAD_IMAGE_BYTES} bytes (it is ${bytes.length})`);
|
|
@@ -23611,13 +23706,15 @@ function uploadImage(relayerUrl, bytes) {
|
|
|
23611
23706
|
if (type === null) throw new RangeError("the image is not a PNG, JPEG, WebP or GIF");
|
|
23612
23707
|
return post(`${base}/image`, new Blob([new Uint8Array(bytes)], { type }), type);
|
|
23613
23708
|
}
|
|
23614
|
-
var MAX_UPLOAD_IMAGE_BYTES;
|
|
23709
|
+
var MAX_UPLOAD_IMAGE_BYTES, AGENT_NAME, AGENT_DESCRIPTION;
|
|
23615
23710
|
var init_publish = __esm({
|
|
23616
23711
|
"../core/src/publish.ts"() {
|
|
23617
23712
|
"use strict";
|
|
23618
23713
|
init_define_OSTRA_PACKAGED();
|
|
23619
23714
|
init_src();
|
|
23620
23715
|
MAX_UPLOAD_IMAGE_BYTES = 1048576;
|
|
23716
|
+
AGENT_NAME = "Ostra Agent";
|
|
23717
|
+
AGENT_DESCRIPTION = "An AI agent with an Ostra post-quantum privacy vault on Robinhood Chain. Its earnings and payments stay in its own vault, signed with one-time keys.";
|
|
23621
23718
|
}
|
|
23622
23719
|
});
|
|
23623
23720
|
|
|
@@ -23692,6 +23789,7 @@ var init_launchpad = __esm({
|
|
|
23692
23789
|
STAND_IN_URI = `ipfs://bafkrei${"a".repeat(52)}`;
|
|
23693
23790
|
LaunchpadService = class {
|
|
23694
23791
|
#client;
|
|
23792
|
+
#logsClient;
|
|
23695
23793
|
#transport;
|
|
23696
23794
|
#config;
|
|
23697
23795
|
#keys;
|
|
@@ -23706,6 +23804,7 @@ var init_launchpad = __esm({
|
|
|
23706
23804
|
constructor(p) {
|
|
23707
23805
|
if (p.creator.kind !== "creator" || p.buyer.kind !== "buyer") throw new Error("the launchpad takes the agent's buyer and creator vaults");
|
|
23708
23806
|
this.#client = p.client;
|
|
23807
|
+
this.#logsClient = p.logsClient ?? p.client;
|
|
23709
23808
|
this.#transport = p.transport;
|
|
23710
23809
|
this.#config = p.config;
|
|
23711
23810
|
this.#keys = p.keys;
|
|
@@ -24494,6 +24593,52 @@ var init_launchpad = __esm({
|
|
|
24494
24593
|
const text3 = await this.#folder.read("agent.json");
|
|
24495
24594
|
return text3 === void 0 ? null : JSON.parse(text3);
|
|
24496
24595
|
}
|
|
24596
|
+
/**
|
|
24597
|
+
* The agent's registration read from the chain when agent.json does not hold it: an identity its creator vault
|
|
24598
|
+
* registered (the Identity Registry's Registered events from the deployment's first block) and still owns. A
|
|
24599
|
+
* registration that landed after its call stopped (the relayer refused the send and a later operation sent the kept
|
|
24600
|
+
* spend, or the process stopped before agent.json was written) is found here and written to agent.json, so the agent
|
|
24601
|
+
* is never registered twice. An identity someone else registered and sent to the creator vault (an ERC-721 transfer
|
|
24602
|
+
* the vault accepts) is no registration of this agent: with no Registered event of the vault, this is null. A
|
|
24603
|
+
* registration sent again just now is read from its receipt instead (#recordFromReceipt), not from logs that may lag.
|
|
24604
|
+
*/
|
|
24605
|
+
async #recoverAgentRecord() {
|
|
24606
|
+
const vault = getAddress24(await this.#creator.vaultAddress());
|
|
24607
|
+
const owned = await this.#client.readContract({ address: ERC8004_IDENTITY_REGISTRY, abi: identityRegistryAbi, functionName: "balanceOf", args: [vault] });
|
|
24608
|
+
if (owned === 0n) return null;
|
|
24609
|
+
const to = await this.#logsClient.getBlockNumber({ cacheTime: 0 });
|
|
24610
|
+
const logs = await getLogsChunked(this.#logsClient, { address: ERC8004_IDENTITY_REGISTRY, event: agentRegisteredEvent, args: { owner: vault }, fromBlock: BigInt(this.#config.deployment.fromBlock), toBlock: to });
|
|
24611
|
+
for (const log2 of logs) {
|
|
24612
|
+
const { agentId, agentURI } = log2.args;
|
|
24613
|
+
const who = await readAgentIdentity(this.#client, agentId);
|
|
24614
|
+
if (who === null || getAddress24(who.owner) !== vault) continue;
|
|
24615
|
+
const record = { agentId: agentId.toString(), uri: agentURI, txHash: log2.transactionHash, at: Math.floor(Date.now() / 1e3) };
|
|
24616
|
+
await this.#folder.write("agent.json", JSON.stringify(record, null, 2));
|
|
24617
|
+
return record;
|
|
24618
|
+
}
|
|
24619
|
+
return null;
|
|
24620
|
+
}
|
|
24621
|
+
/**
|
|
24622
|
+
* The registration transaction `txHash` of the creator vault, read from its receipt (the vault's AgentRegistered
|
|
24623
|
+
* event) and written to agent.json; null when it registered nothing. `uri` is the file it registered with.
|
|
24624
|
+
*/
|
|
24625
|
+
async #recordFromReceipt(txHash, uri2) {
|
|
24626
|
+
const vault = getAddress24(await this.#creator.vaultAddress());
|
|
24627
|
+
const receipt = await this.#client.getTransactionReceipt({ hash: txHash });
|
|
24628
|
+
let agentId;
|
|
24629
|
+
for (const log2 of receipt.logs) {
|
|
24630
|
+
if (getAddress24(log2.address) !== vault) continue;
|
|
24631
|
+
try {
|
|
24632
|
+
const e = decodeEventLog3({ abi: ostraVaultAbi, data: log2.data, topics: log2.topics });
|
|
24633
|
+
if (e.eventName === "AgentRegistered") agentId = e.args.agentId.toString();
|
|
24634
|
+
} catch {
|
|
24635
|
+
}
|
|
24636
|
+
}
|
|
24637
|
+
if (agentId === void 0) return null;
|
|
24638
|
+
const record = { agentId, uri: uri2, txHash, at: Math.floor(Date.now() / 1e3) };
|
|
24639
|
+
await this.#folder.write("agent.json", JSON.stringify(record, null, 2));
|
|
24640
|
+
return record;
|
|
24641
|
+
}
|
|
24497
24642
|
/** The agent's identity: its creator vault, the profile URI it set and its ERC-8004 agent id; or, given `account`, that account's profile URI. */
|
|
24498
24643
|
async profile(accountText) {
|
|
24499
24644
|
const account = accountText === void 0 ? await this.#creator.vaultAddress() : address2(accountText, "account");
|
|
@@ -24510,32 +24655,21 @@ var init_launchpad = __esm({
|
|
|
24510
24655
|
/** Registers the creator vault as an agent in the ERC-8004 Identity Registry, its registration file at `uri`; the vault owns the identity and is its agentWallet. */
|
|
24511
24656
|
async registerAgent(uri2) {
|
|
24512
24657
|
checkUri(uri2);
|
|
24513
|
-
|
|
24514
|
-
const existing = await this.#agentRecord();
|
|
24515
|
-
if (existing !== null) throw new Error(`this agent is registered already as agent ${existing.agentId}:
|
|
24658
|
+
await this.#identityVault();
|
|
24659
|
+
const existing = await this.#agentRecord() ?? await this.#recoverAgentRecord();
|
|
24660
|
+
if (existing !== null) throw new Error(`this agent is registered already as agent ${existing.agentId}: publish_profile publishes its profile again; nothing was signed`);
|
|
24516
24661
|
const r = await this.#simulatedSpend(this.#creator, this.#creatorSender, VAULT_ACTION.REGISTER_AGENT, registerAgentParams(uri2), "agent registration");
|
|
24517
24662
|
if (r.status !== "sent") return r;
|
|
24518
|
-
const
|
|
24519
|
-
|
|
24520
|
-
|
|
24521
|
-
if (getAddress24(log2.address) !== vault) continue;
|
|
24522
|
-
try {
|
|
24523
|
-
const e = decodeEventLog3({ abi: ostraVaultAbi, data: log2.data, topics: log2.topics });
|
|
24524
|
-
if (e.eventName === "AgentRegistered") agentId = e.args.agentId.toString();
|
|
24525
|
-
} catch {
|
|
24526
|
-
}
|
|
24527
|
-
}
|
|
24528
|
-
if (agentId === void 0) throw new Error(`the registration ${r.txHash} landed without an AgentRegistered event`);
|
|
24529
|
-
const record = { agentId, uri: uri2, txHash: r.txHash, at: Math.floor(Date.now() / 1e3) };
|
|
24530
|
-
await this.#folder.write("agent.json", JSON.stringify(record, null, 2));
|
|
24531
|
-
return { ...r, agentId };
|
|
24663
|
+
const record = await this.#recordFromReceipt(r.txHash, uri2);
|
|
24664
|
+
if (record === null) throw new Error(`the registration ${r.txHash} landed without an AgentRegistered event`);
|
|
24665
|
+
return { ...r, agentId: record.agentId };
|
|
24532
24666
|
}
|
|
24533
24667
|
/** Points the agent's ERC-8004 identity at a new registration file. */
|
|
24534
24668
|
async setAgentUri(uri2) {
|
|
24535
24669
|
checkUri(uri2);
|
|
24536
24670
|
await this.#identityVault();
|
|
24537
24671
|
const record = await this.#agentRecord();
|
|
24538
|
-
if (record === null) throw new Error("this agent has no ERC-8004 identity yet:
|
|
24672
|
+
if (record === null) throw new Error("this agent has no ERC-8004 identity yet: publish_profile registers it; nothing was signed");
|
|
24539
24673
|
const r = await this.#simulatedSpend(this.#creator, this.#creatorSender, VAULT_ACTION.SET_AGENT_URI, setAgentUriParams({ agentId: BigInt(record.agentId), uri: uri2 }), "agent registration file");
|
|
24540
24674
|
if (r.status === "sent") await this.#folder.write("agent.json", JSON.stringify({ ...record, uri: uri2, at: Math.floor(Date.now() / 1e3) }, null, 2));
|
|
24541
24675
|
return r;
|
|
@@ -24561,15 +24695,38 @@ var init_launchpad = __esm({
|
|
|
24561
24695
|
if (version < VAULT_VERSION) throw new Error(`the creator vault ${s.vault} runs version ${version}, not ${VAULT_VERSION}; nothing was signed`);
|
|
24562
24696
|
}
|
|
24563
24697
|
/**
|
|
24564
|
-
* Publishes the agent's profile
|
|
24565
|
-
*
|
|
24566
|
-
*
|
|
24698
|
+
* Publishes the agent's Ostra profile, the same for every Ostra agent (profileFile: its name and number, Ostra's
|
|
24699
|
+
* description, its Ostra card, its creator vault as agentWallet), and registers the agent in ERC-8004 when it is not
|
|
24700
|
+
* registered yet: the profile without a number is published, the creator vault registers the agent with it, and the
|
|
24701
|
+
* profile is published again with the agent's number and card, its ERC-8004 identity pointed at it. Called again, it
|
|
24702
|
+
* carries on from where it stopped (what the chain and agent.json hold decides).
|
|
24567
24703
|
*/
|
|
24568
|
-
async publishProfile(
|
|
24569
|
-
const
|
|
24704
|
+
async publishProfile() {
|
|
24705
|
+
const before = await this.#agentRecord() ?? await this.#recoverAgentRecord();
|
|
24706
|
+
if (before !== null) return { agentId: before.agentId, registration: null, unnumbered: null, ...await this.#publishProfileFile(before) };
|
|
24707
|
+
const first = await this.#publishProfileFile(null);
|
|
24708
|
+
const unnumbered = { uri: first.uri, profile: first.profile };
|
|
24709
|
+
if (first.profile.status !== "sent") {
|
|
24710
|
+
const resent = first.profile.status === "resent_pending" ? first.profile.resent : null;
|
|
24711
|
+
const landed = resent !== null && resent.operation === "vault_spend" && resent.action === VAULT_ACTION.REGISTER_AGENT ? await this.#recordFromReceipt(resent.txHash, first.uri) : null;
|
|
24712
|
+
if (landed === null) return { agentId: null, registration: null, unnumbered, ...first };
|
|
24713
|
+
return { agentId: landed.agentId, registration: null, unnumbered, ...await this.#publishProfileFile(landed) };
|
|
24714
|
+
}
|
|
24715
|
+
const registration = await this.registerAgent(first.uri);
|
|
24570
24716
|
const record = await this.#agentRecord();
|
|
24571
|
-
|
|
24717
|
+
if (registration.status !== "sent" || record === null) return { agentId: null, registration, unnumbered, ...first };
|
|
24718
|
+
return { agentId: record.agentId, registration, unnumbered, ...await this.#publishProfileFile(record) };
|
|
24719
|
+
}
|
|
24720
|
+
/**
|
|
24721
|
+
* Builds the profile of the agent (`record`: its registration, or null before it has one), pins it through the
|
|
24722
|
+
* uploader, sets it in OstraRegistry (for the creator vaults of the other pairs it launched from too), and points the
|
|
24723
|
+
* ERC-8004 identity at it when the agent is registered.
|
|
24724
|
+
*/
|
|
24725
|
+
async #publishProfileFile(record) {
|
|
24726
|
+
const vault = await this.#identityVault();
|
|
24727
|
+
const agentId = record?.agentId ?? null;
|
|
24572
24728
|
uploaderUrl(this.#config.relayerUrl);
|
|
24729
|
+
const file = profileFile({ vault, agentId, image: await agentCardUri(this.#config.relayerUrl, agentId) });
|
|
24573
24730
|
const beforeUri = await this.#profileUri(vault);
|
|
24574
24731
|
const before = await readIpfsJson(beforeUri);
|
|
24575
24732
|
if (beforeUri !== null && beforeUri.startsWith("ipfs://") && before === null) throw new Error(`the profile published before (${beforeUri}) cannot be read now, so its Ostrapad listing could not be kept: try again later; nothing was signed`);
|
|
@@ -24927,7 +25084,7 @@ var init_pad2 = __esm({
|
|
|
24927
25084
|
publish(offers) {
|
|
24928
25085
|
return this.#serial(async () => {
|
|
24929
25086
|
const { agentId, creatorVault } = await this.#p.identity();
|
|
24930
|
-
if (agentId === null) throw new Error("this agent is not registered in ERC-8004 yet: publish_profile
|
|
25087
|
+
if (agentId === null) throw new Error("this agent is not registered in ERC-8004 yet: publish_profile registers it; nothing was signed");
|
|
24931
25088
|
const vault = await this.#vault();
|
|
24932
25089
|
const current = await this.#p.currentFile();
|
|
24933
25090
|
if (current === null) throw new Error("this agent has no published profile yet: publish_profile first; nothing was signed");
|
|
@@ -26024,10 +26181,10 @@ var init_raeto = __esm({
|
|
|
26024
26181
|
}
|
|
26025
26182
|
});
|
|
26026
26183
|
|
|
26027
|
-
//
|
|
26184
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/abi.ts
|
|
26028
26185
|
var ostraRouterAbi, ostraStakeAbi, ostraPrivatePoolAbi, OSTRA_SWAP_ESCROW_CREATION_CODE, OSTRA_SHIELD_ESCROW_CREATION_CODE, ostraQuoteBatchAbi, OSTRA_QUOTE_BATCH_CREATION_CODE;
|
|
26029
26186
|
var init_abi2 = __esm({
|
|
26030
|
-
"
|
|
26187
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/abi.ts"() {
|
|
26031
26188
|
"use strict";
|
|
26032
26189
|
init_define_OSTRA_PACKAGED();
|
|
26033
26190
|
ostraRouterAbi = [
|
|
@@ -28892,10 +29049,10 @@ var init_abi2 = __esm({
|
|
|
28892
29049
|
}
|
|
28893
29050
|
});
|
|
28894
29051
|
|
|
28895
|
-
//
|
|
29052
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/constants.ts
|
|
28896
29053
|
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;
|
|
28897
29054
|
var init_constants2 = __esm({
|
|
28898
|
-
"
|
|
29055
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/constants.ts"() {
|
|
28899
29056
|
"use strict";
|
|
28900
29057
|
init_define_OSTRA_PACKAGED();
|
|
28901
29058
|
LOG_WINDOW_BLOCKS2 = 10000000n;
|
|
@@ -28937,11 +29094,11 @@ var init_constants2 = __esm({
|
|
|
28937
29094
|
}
|
|
28938
29095
|
});
|
|
28939
29096
|
|
|
28940
|
-
//
|
|
29097
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/uniswap.ts
|
|
28941
29098
|
import { parseAbi as parseAbi7, parseAbiItem as parseAbiItem6 } from "viem";
|
|
28942
29099
|
var v3FactoryAbi, v3PoolAbi, quoterV2Abi, poolKeyComponents, v4QuoterAbi, exactInputSingleParam, poolManagerAbi, initializeEvent, erc20Abi, multicall3Abi2;
|
|
28943
29100
|
var init_uniswap = __esm({
|
|
28944
|
-
"
|
|
29101
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/uniswap.ts"() {
|
|
28945
29102
|
"use strict";
|
|
28946
29103
|
init_define_OSTRA_PACKAGED();
|
|
28947
29104
|
v3FactoryAbi = parseAbi7(["function getPool(address tokenA, address tokenB, uint24 fee) view returns (address)"]);
|
|
@@ -29033,7 +29190,7 @@ var init_uniswap = __esm({
|
|
|
29033
29190
|
}
|
|
29034
29191
|
});
|
|
29035
29192
|
|
|
29036
|
-
//
|
|
29193
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/legs.ts
|
|
29037
29194
|
import { concatHex, encodeAbiParameters as encodeAbiParameters10, encodePacked as encodePacked4, getAddress as getAddress28, toHex as toHex5 } from "viem";
|
|
29038
29195
|
function legFor(pool, tokenIn, tokenOut, recipient = MSG_SENDER) {
|
|
29039
29196
|
const inAddr = getAddress28(tokenIn);
|
|
@@ -29070,7 +29227,7 @@ function legFor(pool, tokenIn, tokenOut, recipient = MSG_SENDER) {
|
|
|
29070
29227
|
}
|
|
29071
29228
|
var NO_LEG, byte;
|
|
29072
29229
|
var init_legs = __esm({
|
|
29073
|
-
"
|
|
29230
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/legs.ts"() {
|
|
29074
29231
|
"use strict";
|
|
29075
29232
|
init_define_OSTRA_PACKAGED();
|
|
29076
29233
|
init_constants2();
|
|
@@ -29080,7 +29237,7 @@ var init_legs = __esm({
|
|
|
29080
29237
|
}
|
|
29081
29238
|
});
|
|
29082
29239
|
|
|
29083
|
-
//
|
|
29240
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/pools.ts
|
|
29084
29241
|
import { encodeAbiParameters as encodeAbiParameters11, encodeFunctionData as encodeFunctionData12, decodeFunctionResult as decodeFunctionResult3, getAddress as getAddress29, hexToBigInt as hexToBigInt2, keccak256 as keccak25617, toHex as toHex6, zeroAddress as zeroAddress16 } from "viem";
|
|
29085
29242
|
function stateSlot(id, offset) {
|
|
29086
29243
|
const base = hexToBigInt2(keccak25617(encodeAbiParameters11([{ type: "bytes32" }, { type: "uint256" }], [id, POOLS_SLOT3])));
|
|
@@ -29143,7 +29300,7 @@ async function hubPools(client, logsClient, index, token, hub) {
|
|
|
29143
29300
|
}
|
|
29144
29301
|
var POOLS_SLOT3, LIQUIDITY_OFFSET2, PoolIndex;
|
|
29145
29302
|
var init_pools2 = __esm({
|
|
29146
|
-
"
|
|
29303
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/pools.ts"() {
|
|
29147
29304
|
"use strict";
|
|
29148
29305
|
init_define_OSTRA_PACKAGED();
|
|
29149
29306
|
init_constants2();
|
|
@@ -29189,7 +29346,7 @@ var init_pools2 = __esm({
|
|
|
29189
29346
|
}
|
|
29190
29347
|
});
|
|
29191
29348
|
|
|
29192
|
-
//
|
|
29349
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/route.ts
|
|
29193
29350
|
import { decodeAbiParameters as decodeAbiParameters5, decodeFunctionResult as decodeFunctionResult4, encodeDeployData as encodeDeployData2, encodeFunctionData as encodeFunctionData13, getAddress as getAddress30 } from "viem";
|
|
29194
29351
|
function routedToken(token) {
|
|
29195
29352
|
const t = getAddress30(token);
|
|
@@ -29313,7 +29470,7 @@ function routeLegs(route) {
|
|
|
29313
29470
|
}
|
|
29314
29471
|
var NoRouteError, quoteResults;
|
|
29315
29472
|
var init_route = __esm({
|
|
29316
|
-
"
|
|
29473
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/route.ts"() {
|
|
29317
29474
|
"use strict";
|
|
29318
29475
|
init_define_OSTRA_PACKAGED();
|
|
29319
29476
|
init_abi2();
|
|
@@ -29339,7 +29496,7 @@ var init_route = __esm({
|
|
|
29339
29496
|
}
|
|
29340
29497
|
});
|
|
29341
29498
|
|
|
29342
|
-
//
|
|
29499
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/orders.ts
|
|
29343
29500
|
import { encodeAbiParameters as encodeAbiParameters12, encodeFunctionData as encodeFunctionData14, getAddress as getAddress31, getContractAddress as getContractAddress4, isAddress as isAddress14, keccak256 as keccak25618, toHex as toHex7 } from "viem";
|
|
29344
29501
|
function parseSwapDeployment(json) {
|
|
29345
29502
|
const r = json;
|
|
@@ -29393,7 +29550,7 @@ function executeEscrowData(order, route) {
|
|
|
29393
29550
|
}
|
|
29394
29551
|
var ZERO, MAX_UINT32, MAX_UINT64, MAX_STANDING_ORDER_SECONDS, legParam, orderParam;
|
|
29395
29552
|
var init_orders = __esm({
|
|
29396
|
-
"
|
|
29553
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/orders.ts"() {
|
|
29397
29554
|
"use strict";
|
|
29398
29555
|
init_define_OSTRA_PACKAGED();
|
|
29399
29556
|
init_abi2();
|
|
@@ -29432,7 +29589,7 @@ var init_orders = __esm({
|
|
|
29432
29589
|
}
|
|
29433
29590
|
});
|
|
29434
29591
|
|
|
29435
|
-
//
|
|
29592
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/private.ts
|
|
29436
29593
|
import { encodeAbiParameters as encodeAbiParameters13, encodeFunctionData as encodeFunctionData15, getAbiItem, getAddress as getAddress32, getContractAddress as getContractAddress5, keccak256 as keccak25619, parseEventLogs, toHex as toHex8 } from "viem";
|
|
29437
29594
|
function packDigest(elements) {
|
|
29438
29595
|
if (elements.length !== 8) throw new Error("a digest has 8 field elements");
|
|
@@ -29632,7 +29789,7 @@ async function swapOutputNote(prover, sk, outRho, spend, swap, receipt, pool) {
|
|
|
29632
29789
|
}
|
|
29633
29790
|
var FIELD_P, TREE_DEPTH, PRIVATE_SWAP_FEE_BPS, UNSHIELD_DOMAIN, SWAP_DOMAIN, MAX_AMOUNT, MAX_UINT642, ZERO2, noteAddedEvent, PoolTrees;
|
|
29634
29791
|
var init_private = __esm({
|
|
29635
|
-
"
|
|
29792
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/private.ts"() {
|
|
29636
29793
|
"use strict";
|
|
29637
29794
|
init_define_OSTRA_PACKAGED();
|
|
29638
29795
|
init_abi2();
|
|
@@ -29748,19 +29905,19 @@ var init_private = __esm({
|
|
|
29748
29905
|
}
|
|
29749
29906
|
});
|
|
29750
29907
|
|
|
29751
|
-
//
|
|
29908
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/reads.ts
|
|
29752
29909
|
import { getAddress as getAddress33 } from "viem";
|
|
29753
29910
|
var init_reads2 = __esm({
|
|
29754
|
-
"
|
|
29911
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/reads.ts"() {
|
|
29755
29912
|
"use strict";
|
|
29756
29913
|
init_define_OSTRA_PACKAGED();
|
|
29757
29914
|
init_abi2();
|
|
29758
29915
|
}
|
|
29759
29916
|
});
|
|
29760
29917
|
|
|
29761
|
-
//
|
|
29918
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/index.ts
|
|
29762
29919
|
var init_src2 = __esm({
|
|
29763
|
-
"
|
|
29920
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/index.ts"() {
|
|
29764
29921
|
"use strict";
|
|
29765
29922
|
init_define_OSTRA_PACKAGED();
|
|
29766
29923
|
init_abi2();
|
|
@@ -31437,7 +31594,7 @@ var init_strategy2 = __esm({
|
|
|
31437
31594
|
if (who !== null && getAddress37(who.owner) === creatorVault && getAddress37(who.wallet) === creatorVault) return { agentId: id.toString(), creatorVault };
|
|
31438
31595
|
}
|
|
31439
31596
|
throw new StrategyGateError(
|
|
31440
|
-
`Ostra's strategies are for agents registered in the ERC-8004 Identity Registry through Ostra: the creator vault ${creatorVault} must own the agent's identity and be its agentWallet${ids.length === 0 ? " (it has none)" : ` (agent ${ids.map(String).join(", ")} is not)`}. Register with
|
|
31597
|
+
`Ostra's strategies are for agents registered in the ERC-8004 Identity Registry through Ostra: the creator vault ${creatorVault} must own the agent's identity and be its agentWallet${ids.length === 0 ? " (it has none)" : ` (agent ${ids.map(String).join(", ")} is not)`}. Register with publish_profile (it registers the agent), then ask again.`
|
|
31441
31598
|
);
|
|
31442
31599
|
}
|
|
31443
31600
|
// -------------------------------------------------------------------------------------------------------------------
|
|
@@ -32336,7 +32493,7 @@ function refusalOf(reason, outDecimals) {
|
|
|
32336
32493
|
return `revert data ${reason.slice(0, 2 + 8 * 2)}${reason.length > 18 ? "\u2026" : ""} (not one of OstraRouter's errors: from a pool or the Universal Router)`;
|
|
32337
32494
|
}
|
|
32338
32495
|
}
|
|
32339
|
-
var SWAP_DIR, ESCROW_SWAP_GAS, DEFAULT_SWAP_SLIPPAGE_BPS, MAX_SWAP_SLIPPAGE_BPS, DEFAULT_SWAP_MAX_IMPACT_BPS, MAX_SWAP_MAX_IMPACT_BPS, SPLIT_MAX_PARTS, SPLIT_INTERVAL_SECONDS, SPLIT_SLACK_SECONDS, POOL_INDEX2, ORDER_PREFIX, SPLIT_PREFIX, address4, SwapService;
|
|
32496
|
+
var SWAP_DIR, ESCROW_SWAP_GAS, DEFAULT_SWAP_SLIPPAGE_BPS, MAX_SWAP_SLIPPAGE_BPS, DEFAULT_SWAP_MAX_IMPACT_BPS, MAX_SWAP_MAX_IMPACT_BPS, SPLIT_MAX_PARTS, SPLIT_INTERVAL_SECONDS, SPLIT_SLACK_SECONDS, POOL_INDEX2, ORDER_PREFIX, SPLIT_PREFIX, DONE_PREFIX, DONE_ORDERS_KEPT, address4, SwapService;
|
|
32340
32497
|
var init_swap = __esm({
|
|
32341
32498
|
"../core/src/swap.ts"() {
|
|
32342
32499
|
"use strict";
|
|
@@ -32360,6 +32517,8 @@ var init_swap = __esm({
|
|
|
32360
32517
|
POOL_INDEX2 = "pool-index.json";
|
|
32361
32518
|
ORDER_PREFIX = "order-";
|
|
32362
32519
|
SPLIT_PREFIX = "split-";
|
|
32520
|
+
DONE_PREFIX = "done-";
|
|
32521
|
+
DONE_ORDERS_KEPT = 100;
|
|
32363
32522
|
address4 = (text3, what) => {
|
|
32364
32523
|
if (!/^0x[0-9a-fA-F]{40}$/.test(text3)) throw new RangeError(`${what} is not an address`);
|
|
32365
32524
|
return getAddress38(text3);
|
|
@@ -32572,7 +32731,23 @@ var init_swap = __esm({
|
|
|
32572
32731
|
const escrow = escrowAddress(this.#p.swap.router, order);
|
|
32573
32732
|
const execute = executeEscrowData(order, p.route);
|
|
32574
32733
|
await p.from.checkSpend(VAULT_ACTION.TRANSFER, transferParams({ to: escrow, amount: p.amountIn }), "the swap's transfer to its escrow", this.#p.sender);
|
|
32575
|
-
await this.#keep({
|
|
32734
|
+
await this.#keep({
|
|
32735
|
+
version: 1,
|
|
32736
|
+
hash: orderHash(order),
|
|
32737
|
+
escrow,
|
|
32738
|
+
tokenIn: p.tokenIn,
|
|
32739
|
+
amountIn: p.amountIn.toString(),
|
|
32740
|
+
vaultNonce: v.nonce.toString(),
|
|
32741
|
+
deadline: order.deadline.toString(),
|
|
32742
|
+
execute,
|
|
32743
|
+
at: Date.now(),
|
|
32744
|
+
fromBlock: fromBlock.toString(),
|
|
32745
|
+
tokenOut: p.tokenOut,
|
|
32746
|
+
from: vault,
|
|
32747
|
+
to: p.to,
|
|
32748
|
+
inDecimals: p.inDecimals,
|
|
32749
|
+
outDecimals: p.outDecimals
|
|
32750
|
+
});
|
|
32576
32751
|
await o.onOrder?.(orderHash(order), fromBlock, escrow);
|
|
32577
32752
|
const signed = await signVaultTransfer(keychain, v, { chainId, to: escrow, amount: p.amountIn });
|
|
32578
32753
|
const calls = [spendCall(vault, signed), { to: this.#p.swap.router, data: execute }];
|
|
@@ -32601,6 +32776,21 @@ var init_swap = __esm({
|
|
|
32601
32776
|
note: `the swap landed in ${result.txHash}; what it paid could not be read now (${e.message.split("\n")[0]}): do not send it again, its order ${orderHash(placed2)} is read again later`
|
|
32602
32777
|
};
|
|
32603
32778
|
}
|
|
32779
|
+
await this.#keepDone({
|
|
32780
|
+
version: 1,
|
|
32781
|
+
order: orderHash(placed2),
|
|
32782
|
+
txHash: result.txHash,
|
|
32783
|
+
swapped: outcome.swapped,
|
|
32784
|
+
tokenIn: p.tokenIn,
|
|
32785
|
+
tokenOut: p.tokenOut,
|
|
32786
|
+
amountIn: formatUnitsAmount(p.amountIn, p.inDecimals),
|
|
32787
|
+
amountOut: formatUnitsAmount(outcome.amountOut, p.outDecimals),
|
|
32788
|
+
minOut: formatUnitsAmount(p.route.minOut, p.outDecimals),
|
|
32789
|
+
from: p.fromVault,
|
|
32790
|
+
to: p.to,
|
|
32791
|
+
...outcome.swapped ? {} : { refusal: outcome.why ?? "OstraRouter gave no reason" },
|
|
32792
|
+
at: Date.now()
|
|
32793
|
+
});
|
|
32604
32794
|
await this.#p.folder.remove(`${ORDER_PREFIX}${orderHash(placed2)}.json`);
|
|
32605
32795
|
return {
|
|
32606
32796
|
status: "sent",
|
|
@@ -32937,6 +33127,92 @@ var init_swap = __esm({
|
|
|
32937
33127
|
if (swapped) return { swapped, amountOut };
|
|
32938
33128
|
return { swapped, amountOut: 0n, ...reason === null ? {} : { why: refusalOf(reason, outDecimals) } };
|
|
32939
33129
|
}
|
|
33130
|
+
/** Keeps a finished order for ostra_swap_orders, and drops the oldest beyond DONE_ORDERS_KEPT. */
|
|
33131
|
+
async #keepDone(d) {
|
|
33132
|
+
await this.#p.folder.ensure();
|
|
33133
|
+
await this.#p.folder.write(`${DONE_PREFIX}${d.order.toLowerCase()}.json`, `${JSON.stringify(d)}
|
|
33134
|
+
`);
|
|
33135
|
+
const names = (await this.#p.folder.list()).filter((n) => n.startsWith(DONE_PREFIX) && n.endsWith(".json"));
|
|
33136
|
+
if (names.length <= DONE_ORDERS_KEPT) return;
|
|
33137
|
+
const dated = [];
|
|
33138
|
+
for (const n of names) {
|
|
33139
|
+
const text3 = await this.#p.folder.read(n);
|
|
33140
|
+
dated.push({ name: n, at: text3 === void 0 ? 0 : Number(JSON.parse(text3).at) });
|
|
33141
|
+
}
|
|
33142
|
+
dated.sort((a, b) => a.at - b.at);
|
|
33143
|
+
for (const x of dated.slice(0, dated.length - DONE_ORDERS_KEPT)) await this.#p.folder.remove(x.name);
|
|
33144
|
+
}
|
|
33145
|
+
/**
|
|
33146
|
+
* Keeps what a kept order did once the sweep finishes it: from the transaction that executed it (`tx`), else from
|
|
33147
|
+
* OstraRouter's events from the record's block. Best effort: an order whose events cannot be read now is not kept
|
|
33148
|
+
* (a record from before 0.1.12 has no block to search from).
|
|
33149
|
+
*/
|
|
33150
|
+
async #doneFrom(r, tx) {
|
|
33151
|
+
try {
|
|
33152
|
+
let hash = tx;
|
|
33153
|
+
if (hash === null && r.fromBlock !== void 0) {
|
|
33154
|
+
const toBlock = await this.#p.logsClient.getBlockNumber({ cacheTime: 0 });
|
|
33155
|
+
const logs = await getLogsChunked(this.#p.logsClient, { address: this.#p.swap.router, event: getAbiItem2({ abi: ostraRouterAbi, name: "EscrowExecuted" }), args: { orderHash: r.hash }, fromBlock: BigInt(r.fromBlock), toBlock });
|
|
33156
|
+
const moved = logs.find((l) => l.args.received !== 0n);
|
|
33157
|
+
hash = moved === void 0 ? null : moved.transactionHash;
|
|
33158
|
+
}
|
|
33159
|
+
if (hash === null) return;
|
|
33160
|
+
const inDecimals = r.inDecimals ?? await tokenDecimals(this.#p.client, r.tokenIn);
|
|
33161
|
+
const outDecimals = r.outDecimals ?? (r.tokenOut === void 0 ? 18 : await tokenDecimals(this.#p.client, r.tokenOut));
|
|
33162
|
+
const o = await this.#outcome(hash, r.hash, outDecimals);
|
|
33163
|
+
await this.#keepDone({
|
|
33164
|
+
version: 1,
|
|
33165
|
+
order: r.hash,
|
|
33166
|
+
txHash: hash,
|
|
33167
|
+
swapped: o.swapped,
|
|
33168
|
+
tokenIn: r.tokenIn,
|
|
33169
|
+
tokenOut: r.tokenOut ?? null,
|
|
33170
|
+
amountIn: formatUnitsAmount(BigInt(r.amountIn), inDecimals),
|
|
33171
|
+
amountOut: formatUnitsAmount(o.amountOut, outDecimals),
|
|
33172
|
+
minOut: null,
|
|
33173
|
+
from: r.from ?? null,
|
|
33174
|
+
to: r.to ?? null,
|
|
33175
|
+
...o.swapped ? {} : { refusal: o.why ?? "OstraRouter gave no reason" },
|
|
33176
|
+
at: Date.now()
|
|
33177
|
+
});
|
|
33178
|
+
} catch {
|
|
33179
|
+
}
|
|
33180
|
+
}
|
|
33181
|
+
/**
|
|
33182
|
+
* The agent's orders kept here: those not finished (signed or about to be, or landed and being finished; oldest
|
|
33183
|
+
* first) and the finished ones (newest first, at most `limit`). With `order`, that order alone in either list.
|
|
33184
|
+
*/
|
|
33185
|
+
async orders(o = {}) {
|
|
33186
|
+
const want = o.order?.toLowerCase();
|
|
33187
|
+
const open3 = [];
|
|
33188
|
+
const finished = [];
|
|
33189
|
+
for (const name of await this.#p.folder.list()) {
|
|
33190
|
+
const isOrder = name.startsWith(ORDER_PREFIX);
|
|
33191
|
+
if (!isOrder && !name.startsWith(DONE_PREFIX) || !name.endsWith(".json")) continue;
|
|
33192
|
+
if (want !== void 0 && name.slice((isOrder ? ORDER_PREFIX : DONE_PREFIX).length, -".json".length).toLowerCase() !== want) continue;
|
|
33193
|
+
const text3 = await this.#p.folder.read(name);
|
|
33194
|
+
if (text3 === void 0) continue;
|
|
33195
|
+
if (!isOrder) {
|
|
33196
|
+
finished.push(JSON.parse(text3));
|
|
33197
|
+
continue;
|
|
33198
|
+
}
|
|
33199
|
+
const r = JSON.parse(text3);
|
|
33200
|
+
const inDecimals = r.inDecimals ?? await tokenDecimals(this.#p.client, r.tokenIn);
|
|
33201
|
+
const x = { order: r.hash, tokenIn: r.tokenIn, tokenOut: r.tokenOut ?? null, amountIn: formatUnitsAmount(BigInt(r.amountIn), inDecimals), escrow: r.escrow, state: "open", at: r.at };
|
|
33202
|
+
if (r.fromBlock !== void 0) {
|
|
33203
|
+
const res = await this.orderResult(r.hash, BigInt(r.fromBlock), r.escrow);
|
|
33204
|
+
if (res.spent > 0n || res.received > 0n) {
|
|
33205
|
+
x.state = "landed";
|
|
33206
|
+
x.spent = formatUnitsAmount(res.spent, inDecimals);
|
|
33207
|
+
x.received = formatUnitsAmount(res.received, r.outDecimals ?? 18);
|
|
33208
|
+
}
|
|
33209
|
+
}
|
|
33210
|
+
open3.push(x);
|
|
33211
|
+
}
|
|
33212
|
+
open3.sort((a, b) => a.at - b.at);
|
|
33213
|
+
finished.sort((a, b) => b.at - a.at);
|
|
33214
|
+
return { open: open3, finished: finished.slice(0, o.limit ?? 20) };
|
|
33215
|
+
}
|
|
32940
33216
|
/**
|
|
32941
33217
|
* Finishes the orders whose escrow was paid without being executed (a signed spend sent again on its own):
|
|
32942
33218
|
* executeEscrow sends the input along the order's route, or back to its vault past the deadline. Records of orders
|
|
@@ -32953,11 +33229,15 @@ var init_swap = __esm({
|
|
|
32953
33229
|
const nonce = (await this.#p.vaultFor(r.tokenIn).state()).nonce;
|
|
32954
33230
|
const held = await tokenBalance(this.#p.client, r.tokenIn, r.escrow);
|
|
32955
33231
|
if (held >= BigInt(r.amountIn)) {
|
|
32956
|
-
await this.#p.sender.send([{ to: this.#p.swap.router, data: r.execute }]);
|
|
33232
|
+
const tx = await this.#p.sender.send([{ to: this.#p.swap.router, data: r.execute }]);
|
|
33233
|
+
await this.#doneFrom(r, tx);
|
|
32957
33234
|
await this.#p.folder.remove(name);
|
|
32958
33235
|
continue;
|
|
32959
33236
|
}
|
|
32960
|
-
if (nonce !== null && nonce > BigInt(r.vaultNonce))
|
|
33237
|
+
if (nonce !== null && nonce > BigInt(r.vaultNonce)) {
|
|
33238
|
+
await this.#doneFrom(r, null);
|
|
33239
|
+
await this.#p.folder.remove(name);
|
|
33240
|
+
}
|
|
32961
33241
|
} catch (err) {
|
|
32962
33242
|
failures.push({ order: r.hash, error: err instanceof Error ? err.message : String(err) });
|
|
32963
33243
|
}
|
|
@@ -33821,7 +34101,7 @@ var init_backup_cli = __esm({
|
|
|
33821
34101
|
}
|
|
33822
34102
|
});
|
|
33823
34103
|
|
|
33824
|
-
//
|
|
34104
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/cli-prover.ts
|
|
33825
34105
|
import { spawn } from "node:child_process";
|
|
33826
34106
|
function cliProver(binary, timeoutMs = PROVER_TIMEOUT_MS) {
|
|
33827
34107
|
return (command, request) => new Promise((resolve, reject) => {
|
|
@@ -33862,14 +34142,14 @@ function cliProver(binary, timeoutMs = PROVER_TIMEOUT_MS) {
|
|
|
33862
34142
|
}
|
|
33863
34143
|
var PROVER_TIMEOUT_MS;
|
|
33864
34144
|
var init_cli_prover = __esm({
|
|
33865
|
-
"
|
|
34145
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/cli-prover.ts"() {
|
|
33866
34146
|
"use strict";
|
|
33867
34147
|
init_define_OSTRA_PACKAGED();
|
|
33868
34148
|
PROVER_TIMEOUT_MS = 12e4;
|
|
33869
34149
|
}
|
|
33870
34150
|
});
|
|
33871
34151
|
|
|
33872
|
-
//
|
|
34152
|
+
// ../../../../../../srv/apps/ostra-swap/sdk/src/wasm-prover.ts
|
|
33873
34153
|
import { bytesToHex as bytesToHex17 } from "viem";
|
|
33874
34154
|
async function sha256Hex(bytes) {
|
|
33875
34155
|
return bytesToHex17(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)));
|
|
@@ -33905,7 +34185,7 @@ async function wasmProver(glue, bytes, sha2564) {
|
|
|
33905
34185
|
}
|
|
33906
34186
|
var WasmProverTrapped, initialized, trapped;
|
|
33907
34187
|
var init_wasm_prover = __esm({
|
|
33908
|
-
"
|
|
34188
|
+
"../../../../../../srv/apps/ostra-swap/sdk/src/wasm-prover.ts"() {
|
|
33909
34189
|
"use strict";
|
|
33910
34190
|
init_define_OSTRA_PACKAGED();
|
|
33911
34191
|
WasmProverTrapped = class extends Error {
|
|
@@ -34026,7 +34306,7 @@ var init_agent = __esm({
|
|
|
34026
34306
|
this.creator = new VaultService(client, transport, config, p.creatorKeys, creatorSender, "creator");
|
|
34027
34307
|
this.creatorRelayer?.attachBuyerVault(this.creator);
|
|
34028
34308
|
this.creatorChannels = new ChannelService(client, config, p.creatorKeys, this.creator, creatorSender);
|
|
34029
|
-
this.launchpad = config.deployment.launchpad === void 0 ? null : new LaunchpadService({ client, transport, config, keys, buyer: this.buyer, buyerSender: this.sender, creator: this.creator, creatorSender });
|
|
34309
|
+
this.launchpad = config.deployment.launchpad === void 0 ? null : new LaunchpadService({ client, transport, config, keys, buyer: this.buyer, buyerSender: this.sender, creator: this.creator, creatorSender, logsClient: createPublicClient2({ chain: robinhoodChain, transport: http2(config.logsRpcUrl, { retryCount: 6, retryDelay: 2e3 }) }) });
|
|
34030
34310
|
this.shield = new ShieldService(client, config, keys, this.buyer, this.sender);
|
|
34031
34311
|
this.creatorShield = new ShieldService(client, config, keys, this.creator, creatorSender);
|
|
34032
34312
|
this.unshield = new UnshieldService(client, config, keys, this.shield, (index) => this.privateVault(index));
|
|
@@ -34325,6 +34605,12 @@ async function proverConfig(env) {
|
|
|
34325
34605
|
}
|
|
34326
34606
|
return { kind: "wasm", dir, sha256: sha2564 };
|
|
34327
34607
|
}
|
|
34608
|
+
function swapAnswerMs(env) {
|
|
34609
|
+
const v = env.OSTRA_SWAP_ANSWER_MS;
|
|
34610
|
+
if (v === void 0 || v === "") return DEFAULT_SWAP_ANSWER_MS;
|
|
34611
|
+
if (!/^[1-9][0-9]{0,5}$/.test(v) || Number(v) > 6e5) throw new Error("OSTRA_SWAP_ANSWER_MS is a whole number of milliseconds from 1 to 600000");
|
|
34612
|
+
return Number(v);
|
|
34613
|
+
}
|
|
34328
34614
|
function serviceUrl(env, name, fallback) {
|
|
34329
34615
|
const value = env[name];
|
|
34330
34616
|
if (value === void 0 || value === "") return fallback;
|
|
@@ -34374,6 +34660,7 @@ async function loadConfig(env = process.env) {
|
|
|
34374
34660
|
swap,
|
|
34375
34661
|
logsRpcUrl,
|
|
34376
34662
|
privateLocalSpends: env.OSTRA_PRIVATE_LOCAL_SPENDS === "yes",
|
|
34663
|
+
swapAnswerMs: swapAnswerMs(env),
|
|
34377
34664
|
prover,
|
|
34378
34665
|
chainId: deployment.chainId,
|
|
34379
34666
|
rpcUrl: rpcUrl ?? ROBINHOOD_PUBLIC_RPC,
|
|
@@ -34385,7 +34672,7 @@ async function loadConfig(env = process.env) {
|
|
|
34385
34672
|
aiUrl: serviceUrl(env, "OSTRA_AI_URL", services?.aiUrl ?? null)
|
|
34386
34673
|
};
|
|
34387
34674
|
}
|
|
34388
|
-
var PROVER_WASM_FILES, PAD_INDEXER_URL, ETHEREUM_PUBLIC_RPC;
|
|
34675
|
+
var PROVER_WASM_FILES, PAD_INDEXER_URL, ETHEREUM_PUBLIC_RPC, DEFAULT_SWAP_ANSWER_MS;
|
|
34389
34676
|
var init_config2 = __esm({
|
|
34390
34677
|
"src/config.ts"() {
|
|
34391
34678
|
"use strict";
|
|
@@ -34398,10 +34685,12 @@ var init_config2 = __esm({
|
|
|
34398
34685
|
PROVER_WASM_FILES = ["ostra_prove.js", "ostra_prove_bg.wasm"];
|
|
34399
34686
|
PAD_INDEXER_URL = "https://app.ostraagent.xyz";
|
|
34400
34687
|
ETHEREUM_PUBLIC_RPC = "https://ethereum-rpc.publicnode.com";
|
|
34688
|
+
DEFAULT_SWAP_ANSWER_MS = 4e4;
|
|
34401
34689
|
}
|
|
34402
34690
|
});
|
|
34403
34691
|
|
|
34404
34692
|
// src/tools.ts
|
|
34693
|
+
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
34405
34694
|
import { readFile as readFile6, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
34406
34695
|
import { join as join7 } from "node:path";
|
|
34407
34696
|
import { z } from "zod";
|
|
@@ -34445,7 +34734,79 @@ function registerTools(server, agent) {
|
|
|
34445
34734
|
return agent.privateBalance;
|
|
34446
34735
|
};
|
|
34447
34736
|
const opt = (key, value) => value === void 0 ? {} : { [key]: value };
|
|
34448
|
-
const
|
|
34737
|
+
const rpcUrls2 = [agent.config.rpcUrl, agent.config.logsRpcUrl, ...agent.config.ethRpcUrl === null ? [] : [agent.config.ethRpcUrl]];
|
|
34738
|
+
const tool = (name, description, shape, fn) => CLOSED_LAUNCHPAD_TOOLS.has(name) ? void 0 : server.registerTool(name, { description, inputSchema: shape }, ((args) => run2(() => fn(args), rpcUrls2)));
|
|
34739
|
+
const answerMs = agent.config.swapAnswerMs;
|
|
34740
|
+
const swaps = /* @__PURE__ */ new Map();
|
|
34741
|
+
const swapView = (r) => ({
|
|
34742
|
+
swap: r.id,
|
|
34743
|
+
what: r.what,
|
|
34744
|
+
tokenIn: r.tokenIn,
|
|
34745
|
+
tokenOut: r.tokenOut,
|
|
34746
|
+
amount: r.amount,
|
|
34747
|
+
startedAt: new Date(r.startedAt).toISOString(),
|
|
34748
|
+
state: r.endedAt === void 0 ? "running" : r.error === void 0 ? "ended" : "failed",
|
|
34749
|
+
// False while its call still waits for it (a client that gave up on that call learns the result here).
|
|
34750
|
+
answeredPending: r.answered,
|
|
34751
|
+
...r.order === void 0 ? {} : { order: r.order },
|
|
34752
|
+
...r.split === void 0 ? {} : { split: r.split },
|
|
34753
|
+
...r.endedAt === void 0 ? {} : { endedAt: new Date(r.endedAt).toISOString() },
|
|
34754
|
+
...r.result === void 0 ? {} : { result: r.result },
|
|
34755
|
+
...r.error === void 0 ? {} : { error: r.error }
|
|
34756
|
+
});
|
|
34757
|
+
const boundedSwap = async (a, start) => {
|
|
34758
|
+
const busy = [...swaps.values()].find((x) => x.endedAt === void 0 && x.tokenIn.toLowerCase() === a.tokenIn.toLowerCase());
|
|
34759
|
+
if (busy !== void 0) {
|
|
34760
|
+
throw new Error(`a swap from the agent's vault of ${a.tokenIn} is still running (${busy.what} of ${busy.amount}, begun ${new Date(busy.startedAt).toISOString()}): nothing was signed for this call; ostra_swap_orders shows how that one ends, call again once it has`);
|
|
34761
|
+
}
|
|
34762
|
+
const r = { id: randomBytes6(8).toString("hex"), ...a, startedAt: Date.now(), answered: false };
|
|
34763
|
+
swaps.set(r.id, r);
|
|
34764
|
+
const work = Promise.resolve().then(() => start({
|
|
34765
|
+
onOrder: async (order) => {
|
|
34766
|
+
r.order = order;
|
|
34767
|
+
},
|
|
34768
|
+
onSplit: async (id) => {
|
|
34769
|
+
r.split = id;
|
|
34770
|
+
}
|
|
34771
|
+
}));
|
|
34772
|
+
let timer;
|
|
34773
|
+
const late = new Promise((resolve) => {
|
|
34774
|
+
timer = setTimeout(() => resolve(null), answerMs);
|
|
34775
|
+
});
|
|
34776
|
+
let first;
|
|
34777
|
+
try {
|
|
34778
|
+
first = await Promise.race([work.then((value) => ({ value })), late]);
|
|
34779
|
+
} catch (err) {
|
|
34780
|
+
swaps.delete(r.id);
|
|
34781
|
+
throw err;
|
|
34782
|
+
} finally {
|
|
34783
|
+
clearTimeout(timer);
|
|
34784
|
+
}
|
|
34785
|
+
if (first !== null) {
|
|
34786
|
+
swaps.delete(r.id);
|
|
34787
|
+
return first.value;
|
|
34788
|
+
}
|
|
34789
|
+
r.answered = true;
|
|
34790
|
+
work.then(
|
|
34791
|
+
(value) => {
|
|
34792
|
+
r.result = value;
|
|
34793
|
+
r.endedAt = Date.now();
|
|
34794
|
+
},
|
|
34795
|
+
(err) => {
|
|
34796
|
+
r.error = rpcUrls2.reduce((text3, url) => redact(text3, url), err instanceof Error ? err.message : String(err));
|
|
34797
|
+
r.endedAt = Date.now();
|
|
34798
|
+
}
|
|
34799
|
+
);
|
|
34800
|
+
const ended = [...swaps.values()].filter((x) => x.endedAt !== void 0).sort((x, y) => x.endedAt - y.endedAt);
|
|
34801
|
+
for (const x of ended.slice(0, Math.max(0, ended.length - ENDED_SWAPS_KEPT))) swaps.delete(x.id);
|
|
34802
|
+
return {
|
|
34803
|
+
status: "pending",
|
|
34804
|
+
swap: r.id,
|
|
34805
|
+
order: r.order ?? null,
|
|
34806
|
+
split: r.split ?? null,
|
|
34807
|
+
note: `${a.what} is still running after ${answerMs / 1e3} s and goes on in the MCP server: do not send it again. ostra_swap_orders shows how it ends (swap ${r.id}${r.order === void 0 ? "" : `, order ${r.order}`}${r.split === void 0 ? "" : `; split swap ${r.split}: ostra_swap_split list`}).`
|
|
34808
|
+
};
|
|
34809
|
+
};
|
|
34449
34810
|
tool("open_vault", "Creates the agent's vault (USDG on Robinhood Chain, post-quantum WOTS keys) or finds it. With the Ostra relayer, its creation is paid later from the vault.", {}, () => agent.buyer.open());
|
|
34450
34811
|
tool("balance", "The vault's balance, nonce, any operation signed and not landed, the relayer channels, and the creator vault.", {}, async () => ({
|
|
34451
34812
|
vault: await agent.buyer.status(),
|
|
@@ -34539,9 +34900,27 @@ function registerTools(server, agent) {
|
|
|
34539
34900
|
);
|
|
34540
34901
|
tool(
|
|
34541
34902
|
"ostra_swap",
|
|
34542
|
-
|
|
34903
|
+
`Swaps on Ostra Swap from the agent's vault of tokenIn to its vault of tokenOut, as an escrow order of OstraRouter: the vault signs one transfer into the order's escrow and the relayer executes it in the same transaction. The router pays at least minOut or sends the input back; where the tokens go is fixed by the escrow's address. A swap that moves the price more than maxImpactBps (default 1%) is split into up to 16 parts 60 seconds apart, each its own escrow order quoted again right before it is signed: a part waits while it would move the price more than the limit or pay less than the first part's quote less the slippage. The first part runs now and the next ones while the MCP server runs (ostra_swap_split); what is not swapped by the deadline stays in the vault. A swap not done within ${answerMs / 1e3} s answers status "pending" and goes on: do not send it again; ostra_swap_orders tells how it ended.`,
|
|
34543
34904
|
{ tokenIn: swapToken, tokenOut: swapToken, amount: units.describe("in tokenIn"), slippageBps: slippage2, maxImpactBps: maxImpact },
|
|
34544
|
-
(a) =>
|
|
34905
|
+
(a) => {
|
|
34906
|
+
const tokenIn = tokenAddress(a.tokenIn);
|
|
34907
|
+
const tokenOut = tokenAddress(a.tokenOut);
|
|
34908
|
+
return boundedSwap(
|
|
34909
|
+
{ what: "the swap", tokenIn, tokenOut, amount: a.amount },
|
|
34910
|
+
(hooks) => ostraSwap().swap({ tokenIn, tokenOut, amount: a.amount, ...opt("slippageBps", a.slippageBps), ...opt("maxImpactBps", a.maxImpactBps) }, hooks)
|
|
34911
|
+
);
|
|
34912
|
+
}
|
|
34913
|
+
);
|
|
34914
|
+
tool(
|
|
34915
|
+
"ostra_swap_orders",
|
|
34916
|
+
"The agent's Ostra Swap orders: swaps of this MCP server still running (their call waiting, or answered pending) and those that answered pending and then ended or failed, orders kept and not finished (signed or about to be, or landed and being finished by the MCP server's sweep each minute), and the last finished ones with what they spent and paid (refusal: why one did not swap, its input back in the vault). order: that order alone. Nothing is signed.",
|
|
34917
|
+
{ order: bytes323.optional() },
|
|
34918
|
+
async (a) => {
|
|
34919
|
+
const kept = await ostraSwap().orders(a.order === void 0 ? {} : { order: a.order });
|
|
34920
|
+
const want = a.order?.toLowerCase();
|
|
34921
|
+
const pending = [...swaps.values()].filter((x) => want === void 0 || x.order?.toLowerCase() === want).sort((x, y) => y.startedAt - x.startedAt);
|
|
34922
|
+
return { pending: pending.map(swapView), open: kept.open, finished: kept.finished };
|
|
34923
|
+
}
|
|
34545
34924
|
);
|
|
34546
34925
|
tool(
|
|
34547
34926
|
"ostra_swap_split",
|
|
@@ -34706,7 +35085,7 @@ function registerTools(server, agent) {
|
|
|
34706
35085
|
const earnings = z.record(z.string().regex(/^[A-Z]{1,8}$/), z.number().int().min(0)).optional().describe("earnings dates the agent knows, unix seconds by stock ticker (without one NVDA stays at most 60% of its LLTV)");
|
|
34707
35086
|
tool(
|
|
34708
35087
|
"strategy_plan",
|
|
34709
|
-
"Plans what the agent's vaults hold, computed from the chain now: a conservative plan (USDG into a cash vault that passes every check of Strategy 1) and, when a carry of the agent's SPY, QQQ or NVDA may open, a balanced one (Strategy 2: the stock lent to Borro as collateral, USDG borrowed into the cash vault), each with its steps, gas, what it earns in 30 days net of gas, risks, when it stops, and whether OstraBreaker watches (Strategy 3). Every step earns over 3x its gas in 30 days or is left out. The trading capital's cash (trading) stays in the vault. Nothing is signed. Only for an agent registered in ERC-8004 (
|
|
35088
|
+
"Plans what the agent's vaults hold, computed from the chain now: a conservative plan (USDG into a cash vault that passes every check of Strategy 1) and, when a carry of the agent's SPY, QQQ or NVDA may open, a balanced one (Strategy 2: the stock lent to Borro as collateral, USDG borrowed into the cash vault), each with its steps, gas, what it earns in 30 days net of gas, risks, when it stops, and whether OstraBreaker watches (Strategy 3). Every step earns over 3x its gas in 30 days or is left out. The trading capital's cash (trading) stays in the vault. Nothing is signed. Only for an agent registered in ERC-8004 (publish_profile).",
|
|
34710
35089
|
{ buffer: usdg.optional().describe("USDG kept for payments (default: what the vault spent over 7 days)"), earnings },
|
|
34711
35090
|
(a) => agent.strategy.plan({
|
|
34712
35091
|
...a.buffer === void 0 ? {} : { buffer: parseUsdg(a.buffer) },
|
|
@@ -34728,7 +35107,7 @@ function registerTools(server, agent) {
|
|
|
34728
35107
|
const bpsLimit = z.number().int().min(1).max(1e4).optional();
|
|
34729
35108
|
tool(
|
|
34730
35109
|
"trading",
|
|
34731
|
-
`The trading capital: USDG of the vault set aside for trades the agent decides, with Ostra's limits (an agent may only tighten them): a position at most 25% of the capital (positionMaxBps) and no larger than a buy whose quote moves the price 1% (maxImpactBps); buys stop for the day after a 5% loss of the capital that day (dailyLossBps) and for the week after 10% that week (weeklyLossBps). set: sets it (capital in USDG, the limits), only with no position open; the plans keep its cash out of the cash vaults. status: its value now (cash, positions at the quote of selling them), whether buys may happen and, with token, the most that position may be. buy: buys token with amount USDG of the capital, refused past those limits. sell: sells amount (or "all") of the capital's token, split like any large swap. end: ends it (positions stay in their vaults, untracked). Trades go through Ostra Swap; only for an agent registered in ERC-8004 (
|
|
35110
|
+
`The trading capital: USDG of the vault set aside for trades the agent decides, with Ostra's limits (an agent may only tighten them): a position at most 25% of the capital (positionMaxBps) and no larger than a buy whose quote moves the price 1% (maxImpactBps); buys stop for the day after a 5% loss of the capital that day (dailyLossBps) and for the week after 10% that week (weeklyLossBps). set: sets it (capital in USDG, the limits), only with no position open; the plans keep its cash out of the cash vaults. status: its value now (cash, positions at the quote of selling them), whether buys may happen and, with token, the most that position may be. buy: buys token with amount USDG of the capital, refused past those limits. sell: sells amount (or "all") of the capital's token, split like any large swap. A buy or sell not done in time (${agent.config.swapAnswerMs / 1e3} s) answers status "pending" and goes on: do not send it again; ostra_swap_orders tells how it ended. end: ends it (positions stay in their vaults, untracked). Trades go through Ostra Swap; only for an agent registered in ERC-8004 (publish_profile) to set it or buy.`,
|
|
34732
35111
|
{
|
|
34733
35112
|
action: z.enum(["set", "status", "buy", "sell", "end"]),
|
|
34734
35113
|
capital: usdg.optional(),
|
|
@@ -34758,9 +35137,11 @@ function registerTools(server, agent) {
|
|
|
34758
35137
|
const token = tokenAddress(a.token);
|
|
34759
35138
|
if (a.action === "buy") {
|
|
34760
35139
|
if (a.amount === "all") throw new RangeError("buy takes an amount of USDG");
|
|
34761
|
-
|
|
35140
|
+
const amount2 = a.amount;
|
|
35141
|
+
return boundedSwap({ what: "the trading buy", tokenIn: USDG, tokenOut: token, amount: amount2 }, () => t.buy({ token, amount: amount2, ...opt("slippageBps", a.slippageBps) }));
|
|
34762
35142
|
}
|
|
34763
|
-
|
|
35143
|
+
const amount = a.amount;
|
|
35144
|
+
return boundedSwap({ what: "the trading sell", tokenIn: token, tokenOut: USDG, amount }, () => t.sell({ token, amount, ...opt("slippageBps", a.slippageBps) }));
|
|
34764
35145
|
}
|
|
34765
35146
|
);
|
|
34766
35147
|
tool("strategy_report", "What the strategies earn: yield per day by route at the rates now, the share growth since the first run that held each cash vault, and each carry's distance to liquidation.", {}, () => agent.strategy.report());
|
|
@@ -34829,7 +35210,7 @@ function registerTools(server, agent) {
|
|
|
34829
35210
|
const files = z.array(z.string().max(200).regex(/^ipfs:\/\/[A-Za-z0-9]+(\/[A-Za-z0-9._-]+)*$/)).max(10).optional().describe("ipfs:// files (upload_image makes one)");
|
|
34830
35211
|
tool(
|
|
34831
35212
|
"pad_publish",
|
|
34832
|
-
"Ostrapad as a provider. publish: lists offers in the agent's ERC-8004 registration file, paid into its USDG vault (the vault approves the listing once, so a listing is its own); needs publish_profile
|
|
35213
|
+
"Ostrapad as a provider. publish: lists offers in the agent's ERC-8004 registration file, paid into its USDG vault (the vault approves the listing once, so a listing is its own); needs publish_profile first (it registers the agent), and USDG in the creator vault for its relayed transactions (checked before the approval). unpublish: removes the listing. status: the agent's own listing as clients read it. bond / withdraw_bond: a voluntary provider bond (raises the limit per job to the bond, up to 500 USDG; a rejected job costs it 10% of the budget plus the evaluator fee). return_bond_box: returns USDG left in the provider bond box (a deposit whose second step failed) to the USDG vault.",
|
|
34833
35214
|
{ action: z.enum(["publish", "unpublish", "status", "bond", "withdraw_bond", "return_bond_box"]), offers: z.array(offer).min(1).max(20).optional(), amount: usdg.optional() },
|
|
34834
35215
|
async (a) => {
|
|
34835
35216
|
if (a.action === "publish") {
|
|
@@ -34979,17 +35360,9 @@ function registerTools(server, agent) {
|
|
|
34979
35360
|
(a) => lp().tokenInfo(a.token)
|
|
34980
35361
|
);
|
|
34981
35362
|
tool("profile", "The agent's public identity, its creator vault: the profile URI it set, that profile read from IPFS, and its ERC-8004 agent id; or another account's profile.", { account: address5.optional() }, (a) => lp().profile(a.account));
|
|
34982
|
-
tool(
|
|
34983
|
-
"set_profile",
|
|
34984
|
-
"Sets the agent's profile in OstraRegistry from its creator vault, with a WOTS-signed spend: uri is an ipfs:// (or https://) JSON file with name, description, image and links, ideally an ERC-8004 registration file.",
|
|
34985
|
-
{ uri },
|
|
34986
|
-
(a) => lp().setProfile(a.uri)
|
|
34987
|
-
);
|
|
34988
|
-
tool("register_agent", "Registers the agent in the ERC-8004 Identity Registry, once: its creator vault owns the identity and is its agentWallet; uri is its ERC-8004 registration file.", { uri }, (a) => lp().registerAgent(a.uri));
|
|
34989
|
-
tool("set_agent_uri", "Points the agent's ERC-8004 identity at a new registration file.", { uri }, (a) => lp().setAgentUri(a.uri));
|
|
34990
35363
|
tool(
|
|
34991
35364
|
"upload_image",
|
|
34992
|
-
`Pins an image file on this machine (PNG, JPEG, WebP or GIF, at most ${MAX_UPLOAD_IMAGE_BYTES} bytes) to IPFS through the Ostra uploader and returns its ipfs:// URI, for
|
|
35365
|
+
`Pins an image file on this machine (PNG, JPEG, WebP or GIF, at most ${MAX_UPLOAD_IMAGE_BYTES} bytes) to IPFS through the Ostra uploader and returns its ipfs:// URI, for the files of an Ostrapad order or delivery.`,
|
|
34993
35366
|
{ path: z.string().min(1).max(4096) },
|
|
34994
35367
|
async (a) => {
|
|
34995
35368
|
const s = await stat4(a.path);
|
|
@@ -34999,9 +35372,9 @@ function registerTools(server, agent) {
|
|
|
34999
35372
|
);
|
|
35000
35373
|
tool(
|
|
35001
35374
|
"publish_profile",
|
|
35002
|
-
|
|
35003
|
-
{
|
|
35004
|
-
(
|
|
35375
|
+
`Publishes the agent's Ostra profile and registers it in the ERC-8004 Identity Registry, with nothing to fill in: the same for every Ostra agent ("Ostra Agent #<id>", Ostra's description, the Ostra agent card as its image, its creator vault as agentWallet). The first call publishes the profile, registers the agent (its creator vault owns the identity) and publishes the profile again with the agent's number; a later call publishes it again (an Ostrapad listing in it is kept). Needs USDG in the creator vault (fund_creator_vault).`,
|
|
35376
|
+
{},
|
|
35377
|
+
() => lp().publishProfile()
|
|
35005
35378
|
);
|
|
35006
35379
|
tool(
|
|
35007
35380
|
"publish_token_metadata",
|
|
@@ -35064,7 +35437,7 @@ function launchOptions(raw) {
|
|
|
35064
35437
|
}
|
|
35065
35438
|
return out;
|
|
35066
35439
|
}
|
|
35067
|
-
var toJson, address5, usdg, units, pair2, slippage2, bytes323, maxImpact, swapToken, tokenAddress, uri, publicFields, AI_DIR, MAX_VIDEO_BYTES, FINAL_JOB, CLOSED_LAUNCHPAD_TOOLS, BIGINT_FIELDS, ALLOWED_OPTIONS;
|
|
35440
|
+
var toJson, address5, usdg, units, pair2, slippage2, bytes323, maxImpact, swapToken, tokenAddress, uri, publicFields, AI_DIR, MAX_VIDEO_BYTES, FINAL_JOB, CLOSED_LAUNCHPAD_TOOLS, ENDED_SWAPS_KEPT, BIGINT_FIELDS, ALLOWED_OPTIONS;
|
|
35068
35441
|
var init_tools = __esm({
|
|
35069
35442
|
"src/tools.ts"() {
|
|
35070
35443
|
"use strict";
|
|
@@ -35117,6 +35490,7 @@ var init_tools = __esm({
|
|
|
35117
35490
|
"airdrop_fund",
|
|
35118
35491
|
"airdrop_start"
|
|
35119
35492
|
]);
|
|
35493
|
+
ENDED_SWAPS_KEPT = 20;
|
|
35120
35494
|
BIGINT_FIELDS = /* @__PURE__ */ new Set(["minDividendBalance", "maxBuy", "maxWallet", "graduationThreshold"]);
|
|
35121
35495
|
ALLOWED_OPTIONS = /* @__PURE__ */ new Set([
|
|
35122
35496
|
"tiers",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ostraagent/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Ostra Agent's MCP server (stdio): the post-quantum privacy vault for AI agents. One vault to pay, earn, work and hire on Ostrapad, and stay private on Robinhood Chain, with no ETH (the Ostra relayer sends its transactions, paid in USDG).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|