@t2000/sdk 5.16.0 → 5.17.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.cjs +126 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -1
- package/dist/index.d.ts +47 -1
- package/dist/index.js +126 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1226,10 +1226,10 @@ async function finalize(response, opts) {
|
|
|
1226
1226
|
return { status: response.status, body: body2, paid: opts.paid };
|
|
1227
1227
|
}
|
|
1228
1228
|
async function makeGrpcBuildClient(client) {
|
|
1229
|
-
const { SuiGrpcClient:
|
|
1229
|
+
const { SuiGrpcClient: SuiGrpcClient3 } = await import('@mysten/sui/grpc');
|
|
1230
1230
|
const network = client.network === "testnet" ? "testnet" : "mainnet";
|
|
1231
1231
|
const baseUrl = network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
|
|
1232
|
-
return new
|
|
1232
|
+
return new SuiGrpcClient3({ baseUrl, network });
|
|
1233
1233
|
}
|
|
1234
1234
|
function atomicToHuman(raw, decimals) {
|
|
1235
1235
|
return Number(raw) / 10 ** decimals;
|
|
@@ -2030,6 +2030,124 @@ async function listModels(opts) {
|
|
|
2030
2030
|
privacy: m.privacy ?? m.privacy_tier
|
|
2031
2031
|
}));
|
|
2032
2032
|
}
|
|
2033
|
+
var RECEIPT_ANCHORED_SUFFIX = "::anchor::ReceiptAnchored";
|
|
2034
|
+
function fullnodeUrl(network) {
|
|
2035
|
+
return network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
|
|
2036
|
+
}
|
|
2037
|
+
async function verifyReceipt(receiptId, opts = {}) {
|
|
2038
|
+
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
2039
|
+
const network = opts.network ?? "mainnet";
|
|
2040
|
+
const checks = [];
|
|
2041
|
+
let receipt = null;
|
|
2042
|
+
try {
|
|
2043
|
+
const res = await fetch(`${base}/aci/receipts/${encodeURIComponent(receiptId)}`);
|
|
2044
|
+
if (res.ok) {
|
|
2045
|
+
receipt = await res.json();
|
|
2046
|
+
}
|
|
2047
|
+
} catch {
|
|
2048
|
+
}
|
|
2049
|
+
if (!receipt?.event_log) {
|
|
2050
|
+
checks.push({
|
|
2051
|
+
name: "Receipt",
|
|
2052
|
+
status: "fail",
|
|
2053
|
+
detail: "receipt not found or malformed",
|
|
2054
|
+
trust: "receipt-asserted"
|
|
2055
|
+
});
|
|
2056
|
+
return { receiptId, verified: false, anchorVerified: false, checks };
|
|
2057
|
+
}
|
|
2058
|
+
const wireHash = receipt.event_log.find((e) => e.type === "response.returned")?.wire_hash;
|
|
2059
|
+
const workloadId = receipt.workload_id;
|
|
2060
|
+
checks.push({
|
|
2061
|
+
name: "Receipt",
|
|
2062
|
+
status: wireHash && workloadId ? "pass" : "fail",
|
|
2063
|
+
detail: wireHash ? `well-formed (${receipt.event_log.length} log entries, workload ${workloadId})` : "missing response wire_hash / workload_id",
|
|
2064
|
+
trust: "receipt-asserted"
|
|
2065
|
+
});
|
|
2066
|
+
const upstreamEv = receipt.event_log.find((e) => e.type === "upstream.verified");
|
|
2067
|
+
const upstreamOk = upstreamEv?.result === "verified";
|
|
2068
|
+
checks.push({
|
|
2069
|
+
name: "Confidential upstream",
|
|
2070
|
+
status: upstreamEv ? upstreamOk ? "pass" : "fail" : "skip",
|
|
2071
|
+
detail: upstreamEv ? `${upstreamEv.provider ?? upstreamEv.upstream_name ?? "upstream"}: ${upstreamEv.result ?? "unknown"}${upstreamEv.tcb_status ? ` (TCB ${upstreamEv.tcb_status})` : ""}` : "no upstream.verified event (routed/non-confidential?)",
|
|
2072
|
+
trust: "receipt-asserted"
|
|
2073
|
+
});
|
|
2074
|
+
let anchorVerified = false;
|
|
2075
|
+
let anchor;
|
|
2076
|
+
let digest;
|
|
2077
|
+
try {
|
|
2078
|
+
const res = await fetch(`${base}/aci/anchor/${encodeURIComponent(receiptId)}`);
|
|
2079
|
+
if (res.ok) {
|
|
2080
|
+
const j = await res.json();
|
|
2081
|
+
digest = j.txDigest;
|
|
2082
|
+
}
|
|
2083
|
+
} catch {
|
|
2084
|
+
}
|
|
2085
|
+
if (!digest) {
|
|
2086
|
+
checks.push({
|
|
2087
|
+
name: "Sui anchor",
|
|
2088
|
+
status: "fail",
|
|
2089
|
+
detail: `no anchor on record \u2014 POST ${base}/aci/anchor/${receiptId} to create one`,
|
|
2090
|
+
trust: "trustless"
|
|
2091
|
+
});
|
|
2092
|
+
} else {
|
|
2093
|
+
try {
|
|
2094
|
+
const client = new grpc.SuiGrpcClient({ baseUrl: fullnodeUrl(network), network });
|
|
2095
|
+
const tx = await client.core.getTransaction({
|
|
2096
|
+
digest,
|
|
2097
|
+
include: { events: true }
|
|
2098
|
+
});
|
|
2099
|
+
const txn = tx.$kind === "Transaction" ? tx.Transaction : tx.FailedTransaction;
|
|
2100
|
+
const ev = (txn.events ?? []).find(
|
|
2101
|
+
(e) => e.eventType.endsWith(RECEIPT_ANCHORED_SUFFIX)
|
|
2102
|
+
);
|
|
2103
|
+
const data = ev?.json ?? {};
|
|
2104
|
+
const onChainReceipt = String(data.receipt_id ?? "");
|
|
2105
|
+
const onChainWire = String(data.wire_hash ?? "");
|
|
2106
|
+
const onChainWorkload = String(data.workload_id ?? "");
|
|
2107
|
+
const matches = onChainReceipt === receiptId && onChainWire === wireHash && onChainWorkload === workloadId;
|
|
2108
|
+
anchorVerified = matches;
|
|
2109
|
+
anchor = {
|
|
2110
|
+
txDigest: digest,
|
|
2111
|
+
anchoredAtMs: data.anchored_at_ms ? String(data.anchored_at_ms) : void 0,
|
|
2112
|
+
anchoredBy: data.anchored_by ? String(data.anchored_by) : void 0,
|
|
2113
|
+
explorer: `https://suiscan.xyz/${network}/tx/${digest}`
|
|
2114
|
+
};
|
|
2115
|
+
checks.push({
|
|
2116
|
+
name: "Sui anchor",
|
|
2117
|
+
status: matches ? "pass" : "fail",
|
|
2118
|
+
detail: matches ? `on-chain ReceiptAnchored matches (wire_hash + workload_id), tx ${digest}` : `on-chain event does NOT match the receipt (wire ${onChainWire || "absent"})`,
|
|
2119
|
+
trust: "trustless"
|
|
2120
|
+
});
|
|
2121
|
+
} catch (e) {
|
|
2122
|
+
checks.push({
|
|
2123
|
+
name: "Sui anchor",
|
|
2124
|
+
status: "fail",
|
|
2125
|
+
detail: `could not read anchor tx ${digest}: ${e instanceof Error ? e.message : "error"}`,
|
|
2126
|
+
trust: "trustless"
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
checks.push({
|
|
2131
|
+
name: "Receipt signature",
|
|
2132
|
+
status: "skip",
|
|
2133
|
+
detail: receipt.signature ? "present (local recompute via RedPill keyset canonicalization = roadmap)" : "no signature on receipt",
|
|
2134
|
+
trust: "roadmap"
|
|
2135
|
+
});
|
|
2136
|
+
return {
|
|
2137
|
+
receiptId,
|
|
2138
|
+
verified: Boolean(wireHash && workloadId) && anchorVerified,
|
|
2139
|
+
anchorVerified,
|
|
2140
|
+
checks,
|
|
2141
|
+
wireHash,
|
|
2142
|
+
workloadId,
|
|
2143
|
+
upstream: upstreamEv ? {
|
|
2144
|
+
provider: upstreamEv.provider ?? upstreamEv.upstream_name,
|
|
2145
|
+
result: upstreamEv.result,
|
|
2146
|
+
tcbStatus: upstreamEv.tcb_status
|
|
2147
|
+
} : void 0,
|
|
2148
|
+
anchor
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2033
2151
|
var DEFAULT_CONFIG_DIR = path.join(os.homedir(), ".t2000");
|
|
2034
2152
|
function resolveConfigPath(configDir) {
|
|
2035
2153
|
return path.join(configDir ?? DEFAULT_CONFIG_DIR, "config.json");
|
|
@@ -2315,6 +2433,11 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2315
2433
|
async models(opts) {
|
|
2316
2434
|
return listModels(opts);
|
|
2317
2435
|
}
|
|
2436
|
+
/** Verify a confidential response by receipt id — checks the signed receipt
|
|
2437
|
+
* + its trustless on-chain Sui anchor. Fails closed on any mismatch. */
|
|
2438
|
+
async verify(receiptId, opts) {
|
|
2439
|
+
return verifyReceipt(receiptId, opts);
|
|
2440
|
+
}
|
|
2318
2441
|
// -- Swap --
|
|
2319
2442
|
async swap(params) {
|
|
2320
2443
|
this.limits.assert({
|
|
@@ -3202,6 +3325,7 @@ exports.usdcToRaw = usdcToRaw;
|
|
|
3202
3325
|
exports.validateAddress = validateAddress;
|
|
3203
3326
|
exports.validateLabel = validateLabel;
|
|
3204
3327
|
exports.verifyCetusRouteCoinMatch = verifyCetusRouteCoinMatch;
|
|
3328
|
+
exports.verifyReceipt = verifyReceipt;
|
|
3205
3329
|
exports.walletExists = walletExists;
|
|
3206
3330
|
exports.writeLimitsFile = writeLimitsFile;
|
|
3207
3331
|
//# sourceMappingURL=index.cjs.map
|