@toon-protocol/client 0.14.12 → 0.16.0
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/dist/index.d.ts +148 -401
- package/dist/index.js +196 -437
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3957,6 +3957,38 @@ async function readEvmTokenBalance(opts) {
|
|
|
3957
3957
|
if (decimals !== void 0) out.assetScale = Number(decimals);
|
|
3958
3958
|
return out;
|
|
3959
3959
|
}
|
|
3960
|
+
async function readEvmNativeBalance(opts) {
|
|
3961
|
+
const chainId = parseEvmChainId(opts.chainKey);
|
|
3962
|
+
const client = createPublicClient2({
|
|
3963
|
+
transport: http2(opts.rpcUrl),
|
|
3964
|
+
chain: defineChain2({
|
|
3965
|
+
id: chainId,
|
|
3966
|
+
name: opts.chainKey,
|
|
3967
|
+
nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
|
|
3968
|
+
rpcUrls: { default: { http: [opts.rpcUrl] } }
|
|
3969
|
+
})
|
|
3970
|
+
});
|
|
3971
|
+
const wei = await client.getBalance({ address: opts.owner });
|
|
3972
|
+
return { symbol: "ETH", amount: wei.toString(), decimals: 18 };
|
|
3973
|
+
}
|
|
3974
|
+
async function readSolanaNativeBalance(opts) {
|
|
3975
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
3976
|
+
const res = await fetchImpl(opts.rpcUrl, {
|
|
3977
|
+
method: "POST",
|
|
3978
|
+
headers: { "content-type": "application/json" },
|
|
3979
|
+
body: JSON.stringify({
|
|
3980
|
+
jsonrpc: "2.0",
|
|
3981
|
+
id: 1,
|
|
3982
|
+
method: "getBalance",
|
|
3983
|
+
params: [opts.owner, { commitment: "confirmed" }]
|
|
3984
|
+
})
|
|
3985
|
+
});
|
|
3986
|
+
if (!res.ok) throw new Error(`Solana RPC request failed: HTTP ${res.status}`);
|
|
3987
|
+
const json = await res.json();
|
|
3988
|
+
if (json.error) throw new Error(`Solana RPC error: ${json.error.message ?? "unknown"}`);
|
|
3989
|
+
const lamports = BigInt(json.result?.value ?? 0);
|
|
3990
|
+
return { symbol: "SOL", amount: lamports.toString(), decimals: 9 };
|
|
3991
|
+
}
|
|
3960
3992
|
async function readSolanaTokenBalance(opts) {
|
|
3961
3993
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
3962
3994
|
const res = await fetchImpl(opts.rpcUrl, {
|
|
@@ -4004,6 +4036,95 @@ async function readMinaBalance(opts) {
|
|
|
4004
4036
|
assetScale: 9
|
|
4005
4037
|
};
|
|
4006
4038
|
}
|
|
4039
|
+
var errText = (e) => e instanceof Error ? e.message : String(e);
|
|
4040
|
+
function foldNative(out, settled, errors) {
|
|
4041
|
+
if (settled.status === "fulfilled") out.native = settled.value;
|
|
4042
|
+
else errors.push(errText(settled.reason));
|
|
4043
|
+
}
|
|
4044
|
+
function foldToken(out, settled, tokenAddress, errors) {
|
|
4045
|
+
if (settled.status === "rejected") {
|
|
4046
|
+
errors.push(errText(settled.reason));
|
|
4047
|
+
return;
|
|
4048
|
+
}
|
|
4049
|
+
const bal = settled.value;
|
|
4050
|
+
if (!bal) return;
|
|
4051
|
+
out.tokens.push({
|
|
4052
|
+
symbol: bal.asset,
|
|
4053
|
+
amount: bal.amount,
|
|
4054
|
+
decimals: bal.assetScale,
|
|
4055
|
+
...tokenAddress ? { address: tokenAddress } : {}
|
|
4056
|
+
});
|
|
4057
|
+
}
|
|
4058
|
+
function finalizeChain(out, errors) {
|
|
4059
|
+
if (errors.length > 0) out.error = errors[0];
|
|
4060
|
+
if (out.native === void 0 && out.tokens.length === 0) out.unreadable = true;
|
|
4061
|
+
}
|
|
4062
|
+
async function readWalletBalances(sources) {
|
|
4063
|
+
const { fetchImpl } = sources;
|
|
4064
|
+
const tasks = [];
|
|
4065
|
+
if (sources.evm) {
|
|
4066
|
+
const { chainKey, rpcUrl, owner, tokenAddress } = sources.evm;
|
|
4067
|
+
tasks.push(
|
|
4068
|
+
(async () => {
|
|
4069
|
+
const out = { chain: "evm", chainKey, address: owner, tokens: [] };
|
|
4070
|
+
const errors = [];
|
|
4071
|
+
const [nativeR, tokenR] = await Promise.allSettled([
|
|
4072
|
+
readEvmNativeBalance({ rpcUrl, chainKey, owner }),
|
|
4073
|
+
tokenAddress ? readEvmTokenBalance({ rpcUrl, chainKey, tokenAddress, owner }) : Promise.resolve(void 0)
|
|
4074
|
+
]);
|
|
4075
|
+
foldNative(out, nativeR, errors);
|
|
4076
|
+
foldToken(out, tokenR, tokenAddress, errors);
|
|
4077
|
+
finalizeChain(out, errors);
|
|
4078
|
+
return out;
|
|
4079
|
+
})()
|
|
4080
|
+
);
|
|
4081
|
+
}
|
|
4082
|
+
if (sources.solana) {
|
|
4083
|
+
const { chainKey = "solana", rpcUrl, owner, tokenMint } = sources.solana;
|
|
4084
|
+
tasks.push(
|
|
4085
|
+
(async () => {
|
|
4086
|
+
const out = { chain: "solana", chainKey, address: owner, tokens: [] };
|
|
4087
|
+
const errors = [];
|
|
4088
|
+
const [nativeR, tokenR] = await Promise.allSettled([
|
|
4089
|
+
readSolanaNativeBalance({ rpcUrl, owner, fetchImpl }),
|
|
4090
|
+
tokenMint ? readSolanaTokenBalance({ rpcUrl, mint: tokenMint, owner, fetchImpl }) : Promise.resolve(void 0)
|
|
4091
|
+
]);
|
|
4092
|
+
foldNative(out, nativeR, errors);
|
|
4093
|
+
if (tokenR.status === "fulfilled" && tokenR.value && tokenR.value.asset === void 0) {
|
|
4094
|
+
tokenR.value.asset = "USDC";
|
|
4095
|
+
}
|
|
4096
|
+
foldToken(out, tokenR, tokenMint, errors);
|
|
4097
|
+
finalizeChain(out, errors);
|
|
4098
|
+
return out;
|
|
4099
|
+
})()
|
|
4100
|
+
);
|
|
4101
|
+
}
|
|
4102
|
+
if (sources.mina) {
|
|
4103
|
+
const { chainKey = "mina", graphqlUrl, owner } = sources.mina;
|
|
4104
|
+
tasks.push(
|
|
4105
|
+
(async () => {
|
|
4106
|
+
const out = { chain: "mina", chainKey, address: owner, tokens: [] };
|
|
4107
|
+
const errors = [];
|
|
4108
|
+
const nativeR = await Promise.allSettled([readMinaBalance({ graphqlUrl, owner, fetchImpl })]);
|
|
4109
|
+
foldNative(
|
|
4110
|
+
out,
|
|
4111
|
+
nativeR[0].status === "fulfilled" ? {
|
|
4112
|
+
status: "fulfilled",
|
|
4113
|
+
value: {
|
|
4114
|
+
symbol: nativeR[0].value.asset,
|
|
4115
|
+
amount: nativeR[0].value.amount,
|
|
4116
|
+
decimals: nativeR[0].value.assetScale
|
|
4117
|
+
}
|
|
4118
|
+
} : nativeR[0],
|
|
4119
|
+
errors
|
|
4120
|
+
);
|
|
4121
|
+
finalizeChain(out, errors);
|
|
4122
|
+
return out;
|
|
4123
|
+
})()
|
|
4124
|
+
);
|
|
4125
|
+
}
|
|
4126
|
+
return Promise.all(tasks);
|
|
4127
|
+
}
|
|
4007
4128
|
|
|
4008
4129
|
// src/blob-storage.ts
|
|
4009
4130
|
import { buildBlobStorageRequest } from "@toon-protocol/core";
|
|
@@ -5154,6 +5275,74 @@ var ToonClient = class {
|
|
|
5154
5275
|
}
|
|
5155
5276
|
return out;
|
|
5156
5277
|
}
|
|
5278
|
+
/**
|
|
5279
|
+
* The FULL multi-chain wallet view (#299): for every chain the identity is
|
|
5280
|
+
* configured for, the native coin (ETH / SOL / MINA) AND every configured
|
|
5281
|
+
* token (USDC), grouped per chain with the identity's address on that chain.
|
|
5282
|
+
* A superset of {@link getBalances} — which stays scoped to the channel's
|
|
5283
|
+
* settlement token — kept as a separate reader so channel-settlement callers
|
|
5284
|
+
* are unaffected.
|
|
5285
|
+
*
|
|
5286
|
+
* FREE: read-only RPC, no signing, no payment. Works on an UNSTARTED client:
|
|
5287
|
+
* the Solana/Mina addresses (which the signers only register during
|
|
5288
|
+
* `start()`) are derived on demand from the retained mnemonic — the SAME keys
|
|
5289
|
+
* `start()` would register and that `rig fund` prints — so all configured
|
|
5290
|
+
* chains appear even before a start. Best-effort per chain: an unreachable
|
|
5291
|
+
* RPC yields `{ unreadable: true }` for that chain, never failing the others.
|
|
5292
|
+
*/
|
|
5293
|
+
async getWalletBalances() {
|
|
5294
|
+
const sources = {};
|
|
5295
|
+
let derived;
|
|
5296
|
+
let derivedTried = false;
|
|
5297
|
+
const ensureDerived = async () => {
|
|
5298
|
+
if (derivedTried) return derived;
|
|
5299
|
+
derivedTried = true;
|
|
5300
|
+
if (this.config.mnemonic) {
|
|
5301
|
+
derived = await deriveFullIdentity(
|
|
5302
|
+
this.config.mnemonic,
|
|
5303
|
+
this.config.mnemonicAccountIndex ?? 0
|
|
5304
|
+
);
|
|
5305
|
+
}
|
|
5306
|
+
return derived;
|
|
5307
|
+
};
|
|
5308
|
+
const evmAddress = this.getEvmAddress();
|
|
5309
|
+
const rpcUrls = this.config.chainRpcUrls;
|
|
5310
|
+
const tokens = this.config.preferredTokens;
|
|
5311
|
+
if (evmAddress && rpcUrls) {
|
|
5312
|
+
const usableEvm = (c) => c.startsWith("evm") && Boolean(rpcUrls[c]);
|
|
5313
|
+
const settlementKeys = Object.keys(this.config.settlementAddresses ?? {});
|
|
5314
|
+
const chainKeys = this.config.supportedChains ?? Object.keys(rpcUrls);
|
|
5315
|
+
const chainKey = settlementKeys.find(usableEvm) ?? chainKeys.find(usableEvm);
|
|
5316
|
+
if (chainKey && rpcUrls[chainKey]) {
|
|
5317
|
+
sources.evm = {
|
|
5318
|
+
chainKey,
|
|
5319
|
+
rpcUrl: rpcUrls[chainKey],
|
|
5320
|
+
owner: evmAddress,
|
|
5321
|
+
...tokens?.[chainKey] ? { tokenAddress: tokens[chainKey] } : {}
|
|
5322
|
+
};
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
const sol = this.config.solanaChannel;
|
|
5326
|
+
if (sol?.rpcUrl) {
|
|
5327
|
+
const solAddress = this.getSolanaAddress() ?? (await ensureDerived())?.solana.publicKey;
|
|
5328
|
+
if (solAddress) {
|
|
5329
|
+
sources.solana = {
|
|
5330
|
+
chainKey: "solana",
|
|
5331
|
+
rpcUrl: sol.rpcUrl,
|
|
5332
|
+
owner: solAddress,
|
|
5333
|
+
...sol.tokenMint ? { tokenMint: sol.tokenMint } : {}
|
|
5334
|
+
};
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
const mina = this.config.minaChannel;
|
|
5338
|
+
if (mina?.graphqlUrl) {
|
|
5339
|
+
const minaAddress = this.getMinaAddress() ?? (await ensureDerived())?.mina.publicKey;
|
|
5340
|
+
if (minaAddress) {
|
|
5341
|
+
sources.mina = { chainKey: "mina", graphqlUrl: mina.graphqlUrl, owner: minaAddress };
|
|
5342
|
+
}
|
|
5343
|
+
}
|
|
5344
|
+
return readWalletBalances(sources);
|
|
5345
|
+
}
|
|
5157
5346
|
/**
|
|
5158
5347
|
* Resolves an ILP destination address to a peer ID.
|
|
5159
5348
|
* Convention: destination "g.toon.peer1" → peerId "peer1" (last segment).
|
|
@@ -5605,435 +5794,6 @@ var HttpConnectorAdmin = class {
|
|
|
5605
5794
|
}
|
|
5606
5795
|
};
|
|
5607
5796
|
|
|
5608
|
-
// src/pet/filterPetDvmProviders.ts
|
|
5609
|
-
import { parseServiceDiscovery } from "@toon-protocol/core";
|
|
5610
|
-
import { PET_INTERACTION_REQUEST_KIND } from "@toon-protocol/core";
|
|
5611
|
-
function filterPetDvmProviders(events) {
|
|
5612
|
-
const providers = [];
|
|
5613
|
-
for (const event of events) {
|
|
5614
|
-
let parsed;
|
|
5615
|
-
try {
|
|
5616
|
-
parsed = parseServiceDiscovery(event);
|
|
5617
|
-
} catch {
|
|
5618
|
-
continue;
|
|
5619
|
-
}
|
|
5620
|
-
if (!parsed) continue;
|
|
5621
|
-
const skill = parsed.skill;
|
|
5622
|
-
if (!skill) continue;
|
|
5623
|
-
if (!skill.kinds.includes(PET_INTERACTION_REQUEST_KIND)) continue;
|
|
5624
|
-
const pricing = skill.pricing[String(PET_INTERACTION_REQUEST_KIND)] ?? "0";
|
|
5625
|
-
providers.push({
|
|
5626
|
-
ilpAddress: parsed.ilpAddress,
|
|
5627
|
-
pricing,
|
|
5628
|
-
pubkey: event.pubkey,
|
|
5629
|
-
features: skill.features
|
|
5630
|
-
});
|
|
5631
|
-
}
|
|
5632
|
-
providers.sort((a, b) => {
|
|
5633
|
-
const priceA = Number(a.pricing) || 0;
|
|
5634
|
-
const priceB = Number(b.pricing) || 0;
|
|
5635
|
-
return priceA - priceB;
|
|
5636
|
-
});
|
|
5637
|
-
return providers;
|
|
5638
|
-
}
|
|
5639
|
-
|
|
5640
|
-
// src/pet/buildPetInteractionRequest.ts
|
|
5641
|
-
import { PET_INTERACTION_REQUEST_KIND as PET_INTERACTION_REQUEST_KIND2 } from "@toon-protocol/core";
|
|
5642
|
-
var MAX_ACTION_TYPE = 10;
|
|
5643
|
-
function buildPetInteractionRequest(params) {
|
|
5644
|
-
const { blobbiId, actionType, itemId, tokenCost, isSleeping } = params;
|
|
5645
|
-
if (!blobbiId || blobbiId.trim() === "") {
|
|
5646
|
-
throw new ValidationError("blobbiId must be a non-empty string");
|
|
5647
|
-
}
|
|
5648
|
-
if (!Number.isInteger(actionType) || actionType < 0 || actionType > MAX_ACTION_TYPE) {
|
|
5649
|
-
throw new ValidationError(
|
|
5650
|
-
`actionType must be an integer between 0 and ${MAX_ACTION_TYPE}, got ${actionType}`
|
|
5651
|
-
);
|
|
5652
|
-
}
|
|
5653
|
-
if (!Number.isInteger(itemId) || itemId < 0) {
|
|
5654
|
-
throw new ValidationError(
|
|
5655
|
-
`itemId must be a non-negative integer, got ${itemId}`
|
|
5656
|
-
);
|
|
5657
|
-
}
|
|
5658
|
-
if (!Number.isFinite(tokenCost) || tokenCost < 0) {
|
|
5659
|
-
throw new ValidationError(
|
|
5660
|
-
`tokenCost must be a non-negative number, got ${tokenCost}`
|
|
5661
|
-
);
|
|
5662
|
-
}
|
|
5663
|
-
return {
|
|
5664
|
-
kind: PET_INTERACTION_REQUEST_KIND2,
|
|
5665
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
5666
|
-
tags: [
|
|
5667
|
-
["d", blobbiId],
|
|
5668
|
-
["action", String(actionType)],
|
|
5669
|
-
["item", String(itemId)],
|
|
5670
|
-
["cost", String(tokenCost)],
|
|
5671
|
-
["sleeping", String(isSleeping)]
|
|
5672
|
-
],
|
|
5673
|
-
content: ""
|
|
5674
|
-
};
|
|
5675
|
-
}
|
|
5676
|
-
|
|
5677
|
-
// src/pet/parsePetInteractionResult.ts
|
|
5678
|
-
var STAT_FIELDS = [
|
|
5679
|
-
"hunger",
|
|
5680
|
-
"happiness",
|
|
5681
|
-
"health",
|
|
5682
|
-
"hygiene",
|
|
5683
|
-
"energy"
|
|
5684
|
-
];
|
|
5685
|
-
var HEX_64_RE = /^[0-9a-f]{64}$/i;
|
|
5686
|
-
function isValidStats(obj) {
|
|
5687
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
5688
|
-
const record = obj;
|
|
5689
|
-
return STAT_FIELDS.every(
|
|
5690
|
-
(field) => typeof record[field] === "number" && Number.isFinite(record[field])
|
|
5691
|
-
);
|
|
5692
|
-
}
|
|
5693
|
-
function parsePetInteractionResult(data) {
|
|
5694
|
-
if (!data) return null;
|
|
5695
|
-
let json;
|
|
5696
|
-
try {
|
|
5697
|
-
json = atob(data);
|
|
5698
|
-
} catch {
|
|
5699
|
-
return null;
|
|
5700
|
-
}
|
|
5701
|
-
let parsed;
|
|
5702
|
-
try {
|
|
5703
|
-
parsed = JSON.parse(json);
|
|
5704
|
-
} catch {
|
|
5705
|
-
return null;
|
|
5706
|
-
}
|
|
5707
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
5708
|
-
return null;
|
|
5709
|
-
}
|
|
5710
|
-
const record = parsed;
|
|
5711
|
-
if (!isValidStats(record["stats"])) return null;
|
|
5712
|
-
const stage = record["stage"];
|
|
5713
|
-
if (typeof stage !== "number" || !Number.isInteger(stage) || stage < 0 || stage > 2) {
|
|
5714
|
-
return null;
|
|
5715
|
-
}
|
|
5716
|
-
const cycle = record["cycle"];
|
|
5717
|
-
if (typeof cycle !== "number" || !Number.isInteger(cycle) || cycle < 0) {
|
|
5718
|
-
return null;
|
|
5719
|
-
}
|
|
5720
|
-
const lastInteraction = record["lastInteraction"];
|
|
5721
|
-
if (typeof lastInteraction !== "number" || !Number.isFinite(lastInteraction)) {
|
|
5722
|
-
return null;
|
|
5723
|
-
}
|
|
5724
|
-
const brainHash = record["brainHash"];
|
|
5725
|
-
if (typeof brainHash !== "string" || !HEX_64_RE.test(brainHash)) {
|
|
5726
|
-
return null;
|
|
5727
|
-
}
|
|
5728
|
-
const cooldownTimestamps = record["cooldownTimestamps"];
|
|
5729
|
-
if (!Array.isArray(cooldownTimestamps)) return null;
|
|
5730
|
-
if (!cooldownTimestamps.every(
|
|
5731
|
-
(t) => typeof t === "number" && Number.isFinite(t)
|
|
5732
|
-
)) {
|
|
5733
|
-
return null;
|
|
5734
|
-
}
|
|
5735
|
-
const validatedStats = record["stats"];
|
|
5736
|
-
const stats = {
|
|
5737
|
-
hunger: validatedStats.hunger,
|
|
5738
|
-
happiness: validatedStats.happiness,
|
|
5739
|
-
health: validatedStats.health,
|
|
5740
|
-
hygiene: validatedStats.hygiene,
|
|
5741
|
-
energy: validatedStats.energy
|
|
5742
|
-
};
|
|
5743
|
-
return {
|
|
5744
|
-
stats,
|
|
5745
|
-
stage,
|
|
5746
|
-
cycle,
|
|
5747
|
-
lastInteraction,
|
|
5748
|
-
brainHash,
|
|
5749
|
-
cooldownTimestamps: [...cooldownTimestamps]
|
|
5750
|
-
};
|
|
5751
|
-
}
|
|
5752
|
-
|
|
5753
|
-
// src/pet/parsePetInteractionEvent.ts
|
|
5754
|
-
function getTagValue(tags, name) {
|
|
5755
|
-
for (const tag of tags) {
|
|
5756
|
-
if (tag[0] === name) {
|
|
5757
|
-
return tag[1];
|
|
5758
|
-
}
|
|
5759
|
-
}
|
|
5760
|
-
return void 0;
|
|
5761
|
-
}
|
|
5762
|
-
function isStatLike(obj) {
|
|
5763
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
5764
|
-
const r = obj;
|
|
5765
|
-
return typeof r["hunger"] === "number" && Number.isFinite(r["hunger"]) && typeof r["happiness"] === "number" && Number.isFinite(r["happiness"]) && typeof r["health"] === "number" && Number.isFinite(r["health"]) && typeof r["hygiene"] === "number" && Number.isFinite(r["hygiene"]) && typeof r["energy"] === "number" && Number.isFinite(r["energy"]);
|
|
5766
|
-
}
|
|
5767
|
-
function cleanStats(obj) {
|
|
5768
|
-
return {
|
|
5769
|
-
hunger: obj["hunger"],
|
|
5770
|
-
happiness: obj["happiness"],
|
|
5771
|
-
health: obj["health"],
|
|
5772
|
-
hygiene: obj["hygiene"],
|
|
5773
|
-
energy: obj["energy"]
|
|
5774
|
-
};
|
|
5775
|
-
}
|
|
5776
|
-
function parseContent(content) {
|
|
5777
|
-
try {
|
|
5778
|
-
const parsed = JSON.parse(content);
|
|
5779
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
5780
|
-
if (!isStatLike(parsed.priorStats) || !isStatLike(parsed.decayedStats) || !isStatLike(parsed.finalStats)) {
|
|
5781
|
-
return null;
|
|
5782
|
-
}
|
|
5783
|
-
if (typeof parsed.cycle !== "number" || typeof parsed.stage !== "number" || typeof parsed.tokenCost !== "number") {
|
|
5784
|
-
return null;
|
|
5785
|
-
}
|
|
5786
|
-
return {
|
|
5787
|
-
priorStats: cleanStats(parsed.priorStats),
|
|
5788
|
-
decayedStats: cleanStats(parsed.decayedStats),
|
|
5789
|
-
finalStats: cleanStats(parsed.finalStats),
|
|
5790
|
-
cycle: parsed.cycle,
|
|
5791
|
-
stage: parsed.stage,
|
|
5792
|
-
tokenCost: parsed.tokenCost
|
|
5793
|
-
};
|
|
5794
|
-
} catch {
|
|
5795
|
-
return null;
|
|
5796
|
-
}
|
|
5797
|
-
}
|
|
5798
|
-
function parsePetInteractionEvent(event) {
|
|
5799
|
-
const tags = event.tags;
|
|
5800
|
-
const blobbiId = getTagValue(tags, "d");
|
|
5801
|
-
if (!blobbiId) return null;
|
|
5802
|
-
const actionStr = getTagValue(tags, "action");
|
|
5803
|
-
if (!actionStr) return null;
|
|
5804
|
-
const actionType = Number(actionStr);
|
|
5805
|
-
if (!Number.isFinite(actionType)) return null;
|
|
5806
|
-
const itemStr = getTagValue(tags, "item");
|
|
5807
|
-
if (!itemStr) return null;
|
|
5808
|
-
const itemId = Number(itemStr);
|
|
5809
|
-
if (!Number.isFinite(itemId)) return null;
|
|
5810
|
-
const costStr = getTagValue(tags, "cost");
|
|
5811
|
-
if (!costStr) return null;
|
|
5812
|
-
const tokenCost = Number(costStr);
|
|
5813
|
-
if (!Number.isFinite(tokenCost)) return null;
|
|
5814
|
-
const cycleStr = getTagValue(tags, "cycle");
|
|
5815
|
-
if (!cycleStr) return null;
|
|
5816
|
-
const cycle = Number(cycleStr);
|
|
5817
|
-
if (!Number.isFinite(cycle)) return null;
|
|
5818
|
-
const stageStr = getTagValue(tags, "stage");
|
|
5819
|
-
if (!stageStr) return null;
|
|
5820
|
-
const stage = Number(stageStr);
|
|
5821
|
-
if (!Number.isFinite(stage)) return null;
|
|
5822
|
-
const brainHash = getTagValue(tags, "brain_hash");
|
|
5823
|
-
if (!brainHash) return null;
|
|
5824
|
-
const proof = getTagValue(tags, "proof");
|
|
5825
|
-
const minaTx = getTagValue(tags, "mina_tx");
|
|
5826
|
-
const proofStatus = proof && minaTx ? "proven" : "optimistic";
|
|
5827
|
-
const content = parseContent(event.content);
|
|
5828
|
-
const result = {
|
|
5829
|
-
blobbiId,
|
|
5830
|
-
actionType,
|
|
5831
|
-
itemId,
|
|
5832
|
-
tokenCost,
|
|
5833
|
-
cycle,
|
|
5834
|
-
stage,
|
|
5835
|
-
brainHash,
|
|
5836
|
-
proofStatus,
|
|
5837
|
-
content
|
|
5838
|
-
};
|
|
5839
|
-
if (proof) result.proof = proof;
|
|
5840
|
-
if (minaTx) result.minaTx = minaTx;
|
|
5841
|
-
return result;
|
|
5842
|
-
}
|
|
5843
|
-
|
|
5844
|
-
// src/pet/buildPetListingEvent.ts
|
|
5845
|
-
var PET_LISTING_KIND = 30402;
|
|
5846
|
-
var STAGE_NAMES = {
|
|
5847
|
-
0: "Egg",
|
|
5848
|
-
1: "Baby",
|
|
5849
|
-
2: "Adult"
|
|
5850
|
-
};
|
|
5851
|
-
function buildPetListingEvent(params) {
|
|
5852
|
-
const {
|
|
5853
|
-
blobbiId,
|
|
5854
|
-
askPriceUsdc,
|
|
5855
|
-
lifecycleHash,
|
|
5856
|
-
totalSpent,
|
|
5857
|
-
stage,
|
|
5858
|
-
stats,
|
|
5859
|
-
sellerPubkey,
|
|
5860
|
-
relayUrl,
|
|
5861
|
-
expiresAt
|
|
5862
|
-
} = params;
|
|
5863
|
-
const stageName = STAGE_NAMES[stage] ?? "Unknown";
|
|
5864
|
-
const summary = `${stageName} pet for sale \u2014 ${totalSpent} PET tokens spent (verified biography)`;
|
|
5865
|
-
return {
|
|
5866
|
-
kind: PET_LISTING_KIND,
|
|
5867
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
5868
|
-
tags: [
|
|
5869
|
-
["d", blobbiId],
|
|
5870
|
-
["title", `Pet ${blobbiId} for sale`],
|
|
5871
|
-
["price", String(askPriceUsdc), "USDC", ""],
|
|
5872
|
-
["summary", summary],
|
|
5873
|
-
["t", "pet"],
|
|
5874
|
-
["t", "toon-pet"],
|
|
5875
|
-
["lifecycle_hash", lifecycleHash],
|
|
5876
|
-
["total_spent", totalSpent],
|
|
5877
|
-
["stage", String(stage)],
|
|
5878
|
-
["expiration", String(expiresAt)],
|
|
5879
|
-
["relay", relayUrl],
|
|
5880
|
-
["p", sellerPubkey]
|
|
5881
|
-
],
|
|
5882
|
-
content: JSON.stringify(stats)
|
|
5883
|
-
};
|
|
5884
|
-
}
|
|
5885
|
-
|
|
5886
|
-
// src/pet/parsePetListing.ts
|
|
5887
|
-
var HEX_64_RE2 = /^[0-9a-f]{64}$/i;
|
|
5888
|
-
function getTagValue2(tags, name) {
|
|
5889
|
-
for (const tag of tags) {
|
|
5890
|
-
if (tag[0] === name) {
|
|
5891
|
-
return tag[1];
|
|
5892
|
-
}
|
|
5893
|
-
}
|
|
5894
|
-
return void 0;
|
|
5895
|
-
}
|
|
5896
|
-
var DEFAULT_STATS = {
|
|
5897
|
-
hunger: 0,
|
|
5898
|
-
happiness: 0,
|
|
5899
|
-
health: 0,
|
|
5900
|
-
hygiene: 0,
|
|
5901
|
-
energy: 0
|
|
5902
|
-
};
|
|
5903
|
-
function parseStats(content) {
|
|
5904
|
-
try {
|
|
5905
|
-
const parsed = JSON.parse(content);
|
|
5906
|
-
if (typeof parsed !== "object" || parsed === null) return DEFAULT_STATS;
|
|
5907
|
-
const r = parsed;
|
|
5908
|
-
if (typeof r["hunger"] === "number" && typeof r["happiness"] === "number" && typeof r["health"] === "number" && typeof r["hygiene"] === "number" && typeof r["energy"] === "number") {
|
|
5909
|
-
return {
|
|
5910
|
-
hunger: r["hunger"],
|
|
5911
|
-
happiness: r["happiness"],
|
|
5912
|
-
health: r["health"],
|
|
5913
|
-
hygiene: r["hygiene"],
|
|
5914
|
-
energy: r["energy"]
|
|
5915
|
-
};
|
|
5916
|
-
}
|
|
5917
|
-
return DEFAULT_STATS;
|
|
5918
|
-
} catch {
|
|
5919
|
-
return DEFAULT_STATS;
|
|
5920
|
-
}
|
|
5921
|
-
}
|
|
5922
|
-
function parsePetListing(event) {
|
|
5923
|
-
if (event.kind !== 30402) return null;
|
|
5924
|
-
const { tags } = event;
|
|
5925
|
-
const blobbiId = getTagValue2(tags, "d");
|
|
5926
|
-
if (!blobbiId || blobbiId.trim() === "") return null;
|
|
5927
|
-
let askPriceUsdc = 0;
|
|
5928
|
-
let foundPrice = false;
|
|
5929
|
-
for (const tag of tags) {
|
|
5930
|
-
if (tag[0] === "price") {
|
|
5931
|
-
const priceStr = tag[1];
|
|
5932
|
-
if (priceStr === void 0) return null;
|
|
5933
|
-
const parsed = Number(priceStr);
|
|
5934
|
-
if (!Number.isFinite(parsed) || parsed <= 0) return null;
|
|
5935
|
-
askPriceUsdc = parsed;
|
|
5936
|
-
foundPrice = true;
|
|
5937
|
-
break;
|
|
5938
|
-
}
|
|
5939
|
-
}
|
|
5940
|
-
if (!foundPrice) return null;
|
|
5941
|
-
const lifecycleHash = getTagValue2(tags, "lifecycle_hash");
|
|
5942
|
-
if (!lifecycleHash) return null;
|
|
5943
|
-
if (!HEX_64_RE2.test(lifecycleHash)) return null;
|
|
5944
|
-
const totalSpent = getTagValue2(tags, "total_spent");
|
|
5945
|
-
if (totalSpent === void 0 || totalSpent === "") return null;
|
|
5946
|
-
const totalSpentNum = Number(totalSpent);
|
|
5947
|
-
if (!Number.isFinite(totalSpentNum) || totalSpentNum < 0) return null;
|
|
5948
|
-
const stageStr = getTagValue2(tags, "stage");
|
|
5949
|
-
if (stageStr === void 0) return null;
|
|
5950
|
-
const stage = Number(stageStr);
|
|
5951
|
-
if (!Number.isFinite(stage)) return null;
|
|
5952
|
-
const sellerPubkey = getTagValue2(tags, "p") ?? "";
|
|
5953
|
-
const relayUrl = getTagValue2(tags, "relay") ?? "";
|
|
5954
|
-
const expiresAtStr = getTagValue2(tags, "expiration");
|
|
5955
|
-
const expiresAt = expiresAtStr !== void 0 ? Number(expiresAtStr) : 0;
|
|
5956
|
-
const stats = parseStats(event.content);
|
|
5957
|
-
return {
|
|
5958
|
-
blobbiId,
|
|
5959
|
-
askPriceUsdc,
|
|
5960
|
-
lifecycleHash,
|
|
5961
|
-
totalSpent,
|
|
5962
|
-
stage,
|
|
5963
|
-
stats,
|
|
5964
|
-
sellerPubkey,
|
|
5965
|
-
relayUrl,
|
|
5966
|
-
expiresAt,
|
|
5967
|
-
eventId: event.id,
|
|
5968
|
-
createdAt: event.created_at
|
|
5969
|
-
};
|
|
5970
|
-
}
|
|
5971
|
-
|
|
5972
|
-
// src/pet/filterPetListings.ts
|
|
5973
|
-
function compareNumericStrings(a, b) {
|
|
5974
|
-
if (a === b) return 0;
|
|
5975
|
-
try {
|
|
5976
|
-
const bigA = BigInt(a);
|
|
5977
|
-
const bigB = BigInt(b);
|
|
5978
|
-
if (bigA < bigB) return -1;
|
|
5979
|
-
if (bigA > bigB) return 1;
|
|
5980
|
-
return 0;
|
|
5981
|
-
} catch {
|
|
5982
|
-
const fa = Number(a);
|
|
5983
|
-
const fb = Number(b);
|
|
5984
|
-
if (!Number.isFinite(fa) && !Number.isFinite(fb)) return 0;
|
|
5985
|
-
if (!Number.isFinite(fa)) return -1;
|
|
5986
|
-
if (!Number.isFinite(fb)) return 1;
|
|
5987
|
-
return fa - fb;
|
|
5988
|
-
}
|
|
5989
|
-
}
|
|
5990
|
-
function filterPetListings(events, options) {
|
|
5991
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
5992
|
-
const listings = [];
|
|
5993
|
-
for (const event of events) {
|
|
5994
|
-
const listing = parsePetListing(event);
|
|
5995
|
-
if (listing === null) continue;
|
|
5996
|
-
if (listing.expiresAt > 0 && listing.expiresAt < now) continue;
|
|
5997
|
-
if (options?.minStage !== void 0 && listing.stage < options.minStage) {
|
|
5998
|
-
continue;
|
|
5999
|
-
}
|
|
6000
|
-
if (options?.maxAskPriceUsdc !== void 0 && listing.askPriceUsdc > options.maxAskPriceUsdc) {
|
|
6001
|
-
continue;
|
|
6002
|
-
}
|
|
6003
|
-
if (options?.minTotalSpent !== void 0) {
|
|
6004
|
-
if (compareNumericStrings(listing.totalSpent, options.minTotalSpent) < 0) {
|
|
6005
|
-
continue;
|
|
6006
|
-
}
|
|
6007
|
-
}
|
|
6008
|
-
if (options?.sellerPubkey !== void 0 && listing.sellerPubkey !== options.sellerPubkey) {
|
|
6009
|
-
continue;
|
|
6010
|
-
}
|
|
6011
|
-
listings.push(listing);
|
|
6012
|
-
}
|
|
6013
|
-
listings.sort((a, b) => compareNumericStrings(b.totalSpent, a.totalSpent));
|
|
6014
|
-
return listings;
|
|
6015
|
-
}
|
|
6016
|
-
|
|
6017
|
-
// src/pet/buildPetPurchaseRequest.ts
|
|
6018
|
-
import { PET_INTERACTION_REQUEST_KIND as PET_INTERACTION_REQUEST_KIND3 } from "@toon-protocol/core";
|
|
6019
|
-
var TRANSFER_OWNERSHIP_ACTION = 9;
|
|
6020
|
-
function buildPetPurchaseRequest(params) {
|
|
6021
|
-
const { blobbiId, listingEventId, buyerPubkey, tokenCost, sellerPubkey } = params;
|
|
6022
|
-
return {
|
|
6023
|
-
kind: PET_INTERACTION_REQUEST_KIND3,
|
|
6024
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
6025
|
-
tags: [
|
|
6026
|
-
["action", String(TRANSFER_OWNERSHIP_ACTION)],
|
|
6027
|
-
["i", blobbiId],
|
|
6028
|
-
["listing", listingEventId],
|
|
6029
|
-
["buyer", buyerPubkey],
|
|
6030
|
-
["p", sellerPubkey],
|
|
6031
|
-
["cost", String(tokenCost)]
|
|
6032
|
-
],
|
|
6033
|
-
content: ""
|
|
6034
|
-
};
|
|
6035
|
-
}
|
|
6036
|
-
|
|
6037
5797
|
// src/faucet.ts
|
|
6038
5798
|
function defaultFaucetTimeout(chain) {
|
|
6039
5799
|
return chain === "mina" ? 12e4 : 3e4;
|
|
@@ -7173,9 +6933,6 @@ export {
|
|
|
7173
6933
|
buildBackupEvent,
|
|
7174
6934
|
buildBackupFilter,
|
|
7175
6935
|
buildConsentRequest,
|
|
7176
|
-
buildPetInteractionRequest,
|
|
7177
|
-
buildPetListingEvent,
|
|
7178
|
-
buildPetPurchaseRequest,
|
|
7179
6936
|
buildRendererEventTemplate,
|
|
7180
6937
|
buildSettlementInfo,
|
|
7181
6938
|
buildStoreWriteEnvelope,
|
|
@@ -7188,9 +6945,8 @@ export {
|
|
|
7188
6945
|
deriveNostrKeyFromMnemonic,
|
|
7189
6946
|
deterministicGenerator,
|
|
7190
6947
|
encryptMnemonic2 as encryptMnemonic,
|
|
6948
|
+
extractArweaveTxId,
|
|
7191
6949
|
extractUiResource,
|
|
7192
|
-
filterPetDvmProviders,
|
|
7193
|
-
filterPetListings,
|
|
7194
6950
|
fundWallet,
|
|
7195
6951
|
generateKeystore,
|
|
7196
6952
|
generateMnemonic,
|
|
@@ -7208,16 +6964,19 @@ export {
|
|
|
7208
6964
|
parseFulfillHttp,
|
|
7209
6965
|
parseFulfillHttpBytes,
|
|
7210
6966
|
parseHttpResponse,
|
|
7211
|
-
parsePetInteractionEvent,
|
|
7212
|
-
parsePetInteractionResult,
|
|
7213
|
-
parsePetListing,
|
|
7214
6967
|
parseUiCoordinate,
|
|
7215
6968
|
parseX402Body,
|
|
7216
6969
|
parseX402Challenge,
|
|
7217
6970
|
proxyIlpEndpoint,
|
|
7218
6971
|
publishBackCoordinate,
|
|
7219
6972
|
readDiscoveredIlpPeer,
|
|
6973
|
+
readEvmNativeBalance,
|
|
6974
|
+
readEvmTokenBalance,
|
|
6975
|
+
readMinaBalance,
|
|
7220
6976
|
readMinaDepositTotal,
|
|
6977
|
+
readSolanaNativeBalance,
|
|
6978
|
+
readSolanaTokenBalance,
|
|
6979
|
+
readWalletBalances,
|
|
7221
6980
|
renderDeterministicHtml,
|
|
7222
6981
|
renderDispatch,
|
|
7223
6982
|
requestBlobStorage,
|