@t2000/sdk 9.5.0 → 9.7.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/browser.cjs +221 -0
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +210 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +224 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +213 -1
- package/dist/index.js.map +1 -1
- package/dist/{send-DEK6aOGe.d.cts → job-CSq0DRsC.d.cts} +121 -2
- package/dist/{send-DEK6aOGe.d.ts → job-CSq0DRsC.d.ts} +121 -2
- package/package.json +1 -1
package/dist/browser.cjs
CHANGED
|
@@ -390,6 +390,7 @@ var KeypairSigner = class {
|
|
|
390
390
|
constructor(keypair) {
|
|
391
391
|
this.keypair = keypair;
|
|
392
392
|
}
|
|
393
|
+
kind = "keypair";
|
|
393
394
|
getAddress() {
|
|
394
395
|
return this.keypair.getPublicKey().toSuiAddress();
|
|
395
396
|
}
|
|
@@ -413,6 +414,7 @@ var ZkLoginSigner = class {
|
|
|
413
414
|
this.userAddress = userAddress;
|
|
414
415
|
this.maxEpoch = maxEpoch;
|
|
415
416
|
}
|
|
417
|
+
kind = "zklogin";
|
|
416
418
|
getAddress() {
|
|
417
419
|
return this.userAddress;
|
|
418
420
|
}
|
|
@@ -560,6 +562,13 @@ async function payWithMpp(args) {
|
|
|
560
562
|
}
|
|
561
563
|
const headerChallenge = await parseMppSuiChallenge(probe);
|
|
562
564
|
if (headerChallenge) {
|
|
565
|
+
if (signer.kind === "zklogin") {
|
|
566
|
+
throw new exports.T2000Error(
|
|
567
|
+
"DIALECT_UNSUPPORTED",
|
|
568
|
+
"This seller only offers the MPP header dialect, which zkLogin (Passport) wallets cannot safely pay: the seller cannot verify zkLogin signatures, so the payment would settle on-chain without the service delivering. No payment was made. Use an x402-capable service, or pay from a keypair wallet (t2 CLI / MCP).",
|
|
569
|
+
{ dialect: "mpp-header", signerKind: "zklogin" }
|
|
570
|
+
);
|
|
571
|
+
}
|
|
563
572
|
const result = await payViaMppHeader({ signer, client, options });
|
|
564
573
|
await reportDirectPayment(result, options.url);
|
|
565
574
|
return result;
|
|
@@ -1305,15 +1314,218 @@ async function buildSendTx({
|
|
|
1305
1314
|
return tx;
|
|
1306
1315
|
}
|
|
1307
1316
|
|
|
1317
|
+
// src/wallet/job.ts
|
|
1318
|
+
init_errors();
|
|
1319
|
+
init_token_registry();
|
|
1320
|
+
init_coinSelection();
|
|
1321
|
+
var A2A_ESCROW_PACKAGE_ID = process.env.A2A_ESCROW_PACKAGE_ID ?? "0x9e67c380fb7079d793d6d15ff916b24d82779d7119bfa4631863102ed485c0a0";
|
|
1322
|
+
var CLOCK_ID2 = "0x6";
|
|
1323
|
+
var MODULE = "escrow";
|
|
1324
|
+
var MAX_JOB_USDC = 50;
|
|
1325
|
+
var JOB_STATES = [
|
|
1326
|
+
"funded",
|
|
1327
|
+
"delivered",
|
|
1328
|
+
"released",
|
|
1329
|
+
"refunded",
|
|
1330
|
+
"rejected"
|
|
1331
|
+
];
|
|
1332
|
+
function hexToBytes(hex) {
|
|
1333
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
1334
|
+
if (clean.length === 0 || clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {
|
|
1335
|
+
throw new exports.T2000Error(
|
|
1336
|
+
"INVALID_AMOUNT",
|
|
1337
|
+
`Expected a hex hash (0x\u2026), got "${hex.slice(0, 32)}"`
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
const out = [];
|
|
1341
|
+
for (let i = 0; i < clean.length; i += 2) {
|
|
1342
|
+
out.push(Number.parseInt(clean.slice(i, i + 2), 16));
|
|
1343
|
+
}
|
|
1344
|
+
return out;
|
|
1345
|
+
}
|
|
1346
|
+
function bytesToHex(bytes) {
|
|
1347
|
+
let s = "0x";
|
|
1348
|
+
for (const b of bytes) s += b.toString(16).padStart(2, "0");
|
|
1349
|
+
return s;
|
|
1350
|
+
}
|
|
1351
|
+
function preflightCreateJob(terms) {
|
|
1352
|
+
const addressCheck = checkSuiAddress(terms.seller);
|
|
1353
|
+
if (!addressCheck.valid) return addressCheck;
|
|
1354
|
+
if (!Number.isFinite(terms.amountUsdc) || terms.amountUsdc <= 0) {
|
|
1355
|
+
return preflightFail("INVALID_AMOUNT", `Amount must be positive. Got ${terms.amountUsdc}.`);
|
|
1356
|
+
}
|
|
1357
|
+
if (terms.amountUsdc > MAX_JOB_USDC) {
|
|
1358
|
+
return preflightFail(
|
|
1359
|
+
"INVALID_AMOUNT",
|
|
1360
|
+
`v1 caps escrow jobs at ${MAX_JOB_USDC} USDC (no-arbitration split only stays fair at small sizes). Got ${terms.amountUsdc}.`
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
if (terms.deliverByMs <= Date.now()) {
|
|
1364
|
+
return preflightFail("INVALID_AMOUNT", "deliverByMs must be in the future.");
|
|
1365
|
+
}
|
|
1366
|
+
if (terms.reviewWindowMs < 0) {
|
|
1367
|
+
return preflightFail("INVALID_AMOUNT", "reviewWindowMs must be \u2265 0.");
|
|
1368
|
+
}
|
|
1369
|
+
if (!Number.isInteger(terms.rejectSplitBps) || terms.rejectSplitBps < 0 || terms.rejectSplitBps > 1e4) {
|
|
1370
|
+
return preflightFail("INVALID_AMOUNT", "rejectSplitBps must be an integer 0\u201310000.");
|
|
1371
|
+
}
|
|
1372
|
+
try {
|
|
1373
|
+
hexToBytes(terms.specHash);
|
|
1374
|
+
} catch (e) {
|
|
1375
|
+
return preflightFail("INVALID_AMOUNT", e.message);
|
|
1376
|
+
}
|
|
1377
|
+
return PREFLIGHT_OK;
|
|
1378
|
+
}
|
|
1379
|
+
async function buildCreateJobTx({
|
|
1380
|
+
client,
|
|
1381
|
+
buyer,
|
|
1382
|
+
terms
|
|
1383
|
+
}) {
|
|
1384
|
+
const pf = preflightCreateJob(terms);
|
|
1385
|
+
if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
|
|
1386
|
+
const seller = validateAddress(terms.seller);
|
|
1387
|
+
if (seller === validateAddress(buyer)) {
|
|
1388
|
+
throw new exports.T2000Error("INVALID_ADDRESS", "Buyer and seller must be different wallets.");
|
|
1389
|
+
}
|
|
1390
|
+
const rawAmount = BigInt(Math.floor(terms.amountUsdc * 10 ** USDC_DECIMALS));
|
|
1391
|
+
const tx = new transactions.Transaction();
|
|
1392
|
+
const { coin } = await selectAndSplitCoin(tx, client, buyer, exports.USDC_TYPE, rawAmount, {
|
|
1393
|
+
allowSwapAll: false
|
|
1394
|
+
});
|
|
1395
|
+
tx.moveCall({
|
|
1396
|
+
target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::create`,
|
|
1397
|
+
typeArguments: [exports.USDC_TYPE],
|
|
1398
|
+
arguments: [
|
|
1399
|
+
tx.pure.address(seller),
|
|
1400
|
+
coin,
|
|
1401
|
+
tx.pure.vector("u8", hexToBytes(terms.specHash)),
|
|
1402
|
+
tx.pure.u64(terms.deliverByMs),
|
|
1403
|
+
tx.pure.u64(terms.reviewWindowMs),
|
|
1404
|
+
tx.pure.u64(terms.rejectSplitBps),
|
|
1405
|
+
tx.object(CLOCK_ID2)
|
|
1406
|
+
]
|
|
1407
|
+
});
|
|
1408
|
+
return tx;
|
|
1409
|
+
}
|
|
1410
|
+
function jobCall(jobId, fn) {
|
|
1411
|
+
const tx = new transactions.Transaction();
|
|
1412
|
+
tx.moveCall({
|
|
1413
|
+
target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::${fn}`,
|
|
1414
|
+
typeArguments: [exports.USDC_TYPE],
|
|
1415
|
+
arguments: [tx.object(jobId), tx.object(CLOCK_ID2)]
|
|
1416
|
+
});
|
|
1417
|
+
return tx;
|
|
1418
|
+
}
|
|
1419
|
+
function buildDeliverJobTx(jobId, deliveryHash) {
|
|
1420
|
+
const tx = new transactions.Transaction();
|
|
1421
|
+
tx.moveCall({
|
|
1422
|
+
target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::deliver`,
|
|
1423
|
+
typeArguments: [exports.USDC_TYPE],
|
|
1424
|
+
arguments: [
|
|
1425
|
+
tx.object(jobId),
|
|
1426
|
+
tx.pure.vector("u8", hexToBytes(deliveryHash)),
|
|
1427
|
+
tx.object(CLOCK_ID2)
|
|
1428
|
+
]
|
|
1429
|
+
});
|
|
1430
|
+
return tx;
|
|
1431
|
+
}
|
|
1432
|
+
function buildReleaseJobTx(jobId) {
|
|
1433
|
+
return jobCall(jobId, "release");
|
|
1434
|
+
}
|
|
1435
|
+
function buildRejectJobTx(jobId) {
|
|
1436
|
+
return jobCall(jobId, "reject");
|
|
1437
|
+
}
|
|
1438
|
+
function buildRefundJobTx(jobId) {
|
|
1439
|
+
return jobCall(jobId, "refund");
|
|
1440
|
+
}
|
|
1441
|
+
async function getJob(client, jobId) {
|
|
1442
|
+
const resp = await client.core.getObject({ objectId: jobId, include: { json: true } }).catch((e) => {
|
|
1443
|
+
throw new exports.T2000Error(
|
|
1444
|
+
"RPC_ERROR",
|
|
1445
|
+
`Job ${jobId} not found: ${e instanceof Error ? e.message : String(e)}`
|
|
1446
|
+
);
|
|
1447
|
+
});
|
|
1448
|
+
const objType = resp.object?.type ?? "";
|
|
1449
|
+
const json = resp.object?.json;
|
|
1450
|
+
if (!json || !objType.includes(`::${MODULE}::Job<`)) {
|
|
1451
|
+
throw new exports.T2000Error("RPC_ERROR", `Object ${jobId} is not an a2a_escrow Job.`);
|
|
1452
|
+
}
|
|
1453
|
+
const stateNum = Number(json.state ?? -1);
|
|
1454
|
+
const state = JOB_STATES[stateNum];
|
|
1455
|
+
if (!state) {
|
|
1456
|
+
throw new exports.T2000Error("RPC_ERROR", `Job ${jobId} has unknown state ${stateNum}.`);
|
|
1457
|
+
}
|
|
1458
|
+
const deliveredAtMs = Number(json.delivered_at_ms ?? 0);
|
|
1459
|
+
const deliveryBytes = json.delivery_hash ?? [];
|
|
1460
|
+
const hasDelivery = deliveredAtMs > 0;
|
|
1461
|
+
return {
|
|
1462
|
+
id: jobId,
|
|
1463
|
+
buyer: String(json.buyer),
|
|
1464
|
+
seller: String(json.seller),
|
|
1465
|
+
amountUsdc: Number(json.amount) / 10 ** USDC_DECIMALS,
|
|
1466
|
+
escrowUsdc: Number(json.escrow) / 10 ** USDC_DECIMALS,
|
|
1467
|
+
specHash: bytesToHex(json.spec_hash ?? []),
|
|
1468
|
+
deliverByMs: Number(json.deliver_by_ms),
|
|
1469
|
+
reviewWindowMs: Number(json.review_window_ms),
|
|
1470
|
+
rejectSplitBps: Number(json.reject_split_bps),
|
|
1471
|
+
state,
|
|
1472
|
+
deliveryHash: hasDelivery ? bytesToHex(deliveryBytes) : null,
|
|
1473
|
+
deliveredAtMs: hasDelivery ? deliveredAtMs : null,
|
|
1474
|
+
createdAtMs: Number(json.created_at_ms)
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
function jobActionsFor(job, caller, nowMs = Date.now()) {
|
|
1478
|
+
const me = validateAddress(caller);
|
|
1479
|
+
const isBuyer = me === job.buyer;
|
|
1480
|
+
const isSeller = me === job.seller;
|
|
1481
|
+
const actions = [];
|
|
1482
|
+
if (job.state === "funded") {
|
|
1483
|
+
if (isSeller && nowMs <= job.deliverByMs) actions.push("deliver");
|
|
1484
|
+
if (isBuyer) actions.push("release");
|
|
1485
|
+
if (nowMs > job.deliverByMs) actions.push("refund");
|
|
1486
|
+
} else if (job.state === "delivered") {
|
|
1487
|
+
const windowClosesMs = (job.deliveredAtMs ?? 0) + job.reviewWindowMs;
|
|
1488
|
+
if (isBuyer && nowMs <= windowClosesMs) actions.push("release", "reject");
|
|
1489
|
+
if (nowMs > windowClosesMs) actions.push("release");
|
|
1490
|
+
}
|
|
1491
|
+
return actions;
|
|
1492
|
+
}
|
|
1493
|
+
async function verifyJobForSeller({
|
|
1494
|
+
client,
|
|
1495
|
+
jobId,
|
|
1496
|
+
seller,
|
|
1497
|
+
minAmountUsdc,
|
|
1498
|
+
minRunwayMs = 6e4
|
|
1499
|
+
}) {
|
|
1500
|
+
const job = await getJob(client, jobId);
|
|
1501
|
+
const problems = [];
|
|
1502
|
+
if (job.state !== "funded") {
|
|
1503
|
+
problems.push(`state is "${job.state}", expected "funded"`);
|
|
1504
|
+
}
|
|
1505
|
+
if (job.seller !== validateAddress(seller)) {
|
|
1506
|
+
problems.push(`job pays ${job.seller}, not this seller`);
|
|
1507
|
+
}
|
|
1508
|
+
if (job.escrowUsdc < minAmountUsdc) {
|
|
1509
|
+
problems.push(`escrow holds ${job.escrowUsdc} USDC, price is ${minAmountUsdc}`);
|
|
1510
|
+
}
|
|
1511
|
+
if (job.deliverByMs - Date.now() < minRunwayMs) {
|
|
1512
|
+
problems.push("deadline too close to accept");
|
|
1513
|
+
}
|
|
1514
|
+
return { ok: problems.length === 0, job, problems };
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1308
1517
|
// src/browser.ts
|
|
1309
1518
|
init_token_registry();
|
|
1310
1519
|
|
|
1520
|
+
exports.A2A_ESCROW_PACKAGE_ID = A2A_ESCROW_PACKAGE_ID;
|
|
1311
1521
|
exports.CLOCK_ID = CLOCK_ID;
|
|
1312
1522
|
exports.DEFAULT_NETWORK = DEFAULT_NETWORK;
|
|
1313
1523
|
exports.GAS_RESERVE_MIN = GAS_RESERVE_MIN;
|
|
1524
|
+
exports.JOB_STATES = JOB_STATES;
|
|
1314
1525
|
exports.KNOWN_TARGETS = KNOWN_TARGETS;
|
|
1315
1526
|
exports.KeypairSigner = KeypairSigner;
|
|
1316
1527
|
exports.LABEL_PATTERNS = LABEL_PATTERNS;
|
|
1528
|
+
exports.MAX_JOB_USDC = MAX_JOB_USDC;
|
|
1317
1529
|
exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
1318
1530
|
exports.OVERLAY_FEE_RATE = OVERLAY_FEE_RATE;
|
|
1319
1531
|
exports.PREFLIGHT_MAX_AMOUNT = PREFLIGHT_MAX_AMOUNT;
|
|
@@ -1324,6 +1536,11 @@ exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
|
|
|
1324
1536
|
exports.T2000_OVERLAY_FEE_WALLET = T2000_OVERLAY_FEE_WALLET;
|
|
1325
1537
|
exports.USDC_DECIMALS = USDC_DECIMALS;
|
|
1326
1538
|
exports.ZkLoginSigner = ZkLoginSigner;
|
|
1539
|
+
exports.buildCreateJobTx = buildCreateJobTx;
|
|
1540
|
+
exports.buildDeliverJobTx = buildDeliverJobTx;
|
|
1541
|
+
exports.buildRefundJobTx = buildRefundJobTx;
|
|
1542
|
+
exports.buildRejectJobTx = buildRejectJobTx;
|
|
1543
|
+
exports.buildReleaseJobTx = buildReleaseJobTx;
|
|
1327
1544
|
exports.buildSendTx = buildSendTx;
|
|
1328
1545
|
exports.buildSwapTx = buildSwapTx;
|
|
1329
1546
|
exports.checkPositiveAmount = checkPositiveAmount;
|
|
@@ -1344,12 +1561,15 @@ exports.formatUsd = formatUsd;
|
|
|
1344
1561
|
exports.fromBase64 = fromBase642;
|
|
1345
1562
|
exports.getDecimals = getDecimals;
|
|
1346
1563
|
exports.getDecimalsForCoinType = getDecimalsForCoinType;
|
|
1564
|
+
exports.getJob = getJob;
|
|
1565
|
+
exports.jobActionsFor = jobActionsFor;
|
|
1347
1566
|
exports.mapMoveAbortCode = mapMoveAbortCode;
|
|
1348
1567
|
exports.mapWalletError = mapWalletError;
|
|
1349
1568
|
exports.mistToSui = mistToSui;
|
|
1350
1569
|
exports.parseMppSuiChallenge = parseMppSuiChallenge;
|
|
1351
1570
|
exports.parseSuiRpcTx = parseSuiRpcTx;
|
|
1352
1571
|
exports.payWithMpp = payWithMpp;
|
|
1572
|
+
exports.preflightCreateJob = preflightCreateJob;
|
|
1353
1573
|
exports.preflightFail = preflightFail;
|
|
1354
1574
|
exports.preflightPay = preflightPay;
|
|
1355
1575
|
exports.preflightSend = preflightSend;
|
|
@@ -1365,5 +1585,6 @@ exports.toBase64 = toBase64;
|
|
|
1365
1585
|
exports.truncateAddress = truncateAddress;
|
|
1366
1586
|
exports.usdcToRaw = usdcToRaw;
|
|
1367
1587
|
exports.validateAddress = validateAddress;
|
|
1588
|
+
exports.verifyJobForSeller = verifyJobForSeller;
|
|
1368
1589
|
//# sourceMappingURL=browser.cjs.map
|
|
1369
1590
|
//# sourceMappingURL=browser.cjs.map
|