@t2000/sdk 9.6.0 → 9.7.1

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 CHANGED
@@ -3131,6 +3131,210 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
3131
3131
 
3132
3132
  // src/index.ts
3133
3133
  init_errors();
3134
+
3135
+ // src/wallet/job.ts
3136
+ init_errors();
3137
+ init_token_registry();
3138
+ init_preflight();
3139
+ init_coinSelection();
3140
+ var A2A_ESCROW_PACKAGE_ID = process.env.A2A_ESCROW_PACKAGE_ID ?? "0x9e67c380fb7079d793d6d15ff916b24d82779d7119bfa4631863102ed485c0a0";
3141
+ var CLOCK_ID2 = "0x6";
3142
+ var MODULE = "escrow";
3143
+ var MAX_JOB_USDC = 50;
3144
+ var JOB_STATES = [
3145
+ "funded",
3146
+ "delivered",
3147
+ "released",
3148
+ "refunded",
3149
+ "rejected"
3150
+ ];
3151
+ function hexToBytes2(hex) {
3152
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
3153
+ if (clean.length === 0 || clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {
3154
+ throw new exports.T2000Error(
3155
+ "INVALID_AMOUNT",
3156
+ `Expected a hex hash (0x\u2026), got "${hex.slice(0, 32)}"`
3157
+ );
3158
+ }
3159
+ const out = [];
3160
+ for (let i = 0; i < clean.length; i += 2) {
3161
+ out.push(Number.parseInt(clean.slice(i, i + 2), 16));
3162
+ }
3163
+ return out;
3164
+ }
3165
+ function bytesToHex2(bytes) {
3166
+ const arr = typeof bytes === "string" ? Array.from(atob(bytes), (c) => c.charCodeAt(0)) : bytes;
3167
+ let s = "0x";
3168
+ for (const b of arr) s += b.toString(16).padStart(2, "0");
3169
+ return s;
3170
+ }
3171
+ function preflightCreateJob(terms) {
3172
+ const addressCheck = checkSuiAddress(terms.seller);
3173
+ if (!addressCheck.valid) return addressCheck;
3174
+ if (!Number.isFinite(terms.amountUsdc) || terms.amountUsdc <= 0) {
3175
+ return preflightFail("INVALID_AMOUNT", `Amount must be positive. Got ${terms.amountUsdc}.`);
3176
+ }
3177
+ if (terms.amountUsdc > MAX_JOB_USDC) {
3178
+ return preflightFail(
3179
+ "INVALID_AMOUNT",
3180
+ `v1 caps escrow jobs at ${MAX_JOB_USDC} USDC (no-arbitration split only stays fair at small sizes). Got ${terms.amountUsdc}.`
3181
+ );
3182
+ }
3183
+ if (terms.deliverByMs <= Date.now()) {
3184
+ return preflightFail("INVALID_AMOUNT", "deliverByMs must be in the future.");
3185
+ }
3186
+ if (terms.reviewWindowMs < 0) {
3187
+ return preflightFail("INVALID_AMOUNT", "reviewWindowMs must be \u2265 0.");
3188
+ }
3189
+ if (!Number.isInteger(terms.rejectSplitBps) || terms.rejectSplitBps < 0 || terms.rejectSplitBps > 1e4) {
3190
+ return preflightFail("INVALID_AMOUNT", "rejectSplitBps must be an integer 0\u201310000.");
3191
+ }
3192
+ try {
3193
+ hexToBytes2(terms.specHash);
3194
+ } catch (e) {
3195
+ return preflightFail("INVALID_AMOUNT", e.message);
3196
+ }
3197
+ return exports.PREFLIGHT_OK;
3198
+ }
3199
+ async function buildCreateJobTx({
3200
+ client,
3201
+ buyer,
3202
+ terms
3203
+ }) {
3204
+ const pf = preflightCreateJob(terms);
3205
+ if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
3206
+ const seller = validateAddress(terms.seller);
3207
+ if (seller === validateAddress(buyer)) {
3208
+ throw new exports.T2000Error("INVALID_ADDRESS", "Buyer and seller must be different wallets.");
3209
+ }
3210
+ const rawAmount = BigInt(Math.floor(terms.amountUsdc * 10 ** USDC_DECIMALS));
3211
+ const tx = new transactions.Transaction();
3212
+ const { coin } = await selectAndSplitCoin(tx, client, buyer, exports.USDC_TYPE, rawAmount, {
3213
+ allowSwapAll: false
3214
+ });
3215
+ tx.moveCall({
3216
+ target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::create`,
3217
+ typeArguments: [exports.USDC_TYPE],
3218
+ arguments: [
3219
+ tx.pure.address(seller),
3220
+ coin,
3221
+ tx.pure.vector("u8", hexToBytes2(terms.specHash)),
3222
+ tx.pure.u64(terms.deliverByMs),
3223
+ tx.pure.u64(terms.reviewWindowMs),
3224
+ tx.pure.u64(terms.rejectSplitBps),
3225
+ tx.object(CLOCK_ID2)
3226
+ ]
3227
+ });
3228
+ return tx;
3229
+ }
3230
+ function jobCall(jobId, fn) {
3231
+ const tx = new transactions.Transaction();
3232
+ tx.moveCall({
3233
+ target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::${fn}`,
3234
+ typeArguments: [exports.USDC_TYPE],
3235
+ arguments: [tx.object(jobId), tx.object(CLOCK_ID2)]
3236
+ });
3237
+ return tx;
3238
+ }
3239
+ function buildDeliverJobTx(jobId, deliveryHash) {
3240
+ const tx = new transactions.Transaction();
3241
+ tx.moveCall({
3242
+ target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::deliver`,
3243
+ typeArguments: [exports.USDC_TYPE],
3244
+ arguments: [
3245
+ tx.object(jobId),
3246
+ tx.pure.vector("u8", hexToBytes2(deliveryHash)),
3247
+ tx.object(CLOCK_ID2)
3248
+ ]
3249
+ });
3250
+ return tx;
3251
+ }
3252
+ function buildReleaseJobTx(jobId) {
3253
+ return jobCall(jobId, "release");
3254
+ }
3255
+ function buildRejectJobTx(jobId) {
3256
+ return jobCall(jobId, "reject");
3257
+ }
3258
+ function buildRefundJobTx(jobId) {
3259
+ return jobCall(jobId, "refund");
3260
+ }
3261
+ async function getJob(client, jobId) {
3262
+ const resp = await client.core.getObject({ objectId: jobId, include: { json: true } }).catch((e) => {
3263
+ throw new exports.T2000Error(
3264
+ "RPC_ERROR",
3265
+ `Job ${jobId} not found: ${e instanceof Error ? e.message : String(e)}`
3266
+ );
3267
+ });
3268
+ const objType = resp.object?.type ?? "";
3269
+ const json = resp.object?.json;
3270
+ if (!json || !objType.includes(`::${MODULE}::Job<`)) {
3271
+ throw new exports.T2000Error("RPC_ERROR", `Object ${jobId} is not an a2a_escrow Job.`);
3272
+ }
3273
+ const stateNum = Number(json.state ?? -1);
3274
+ const state = JOB_STATES[stateNum];
3275
+ if (!state) {
3276
+ throw new exports.T2000Error("RPC_ERROR", `Job ${jobId} has unknown state ${stateNum}.`);
3277
+ }
3278
+ const deliveredAtMs = Number(json.delivered_at_ms ?? 0);
3279
+ const deliveryBytes = json.delivery_hash ?? [];
3280
+ const hasDelivery = deliveredAtMs > 0;
3281
+ return {
3282
+ id: jobId,
3283
+ buyer: String(json.buyer),
3284
+ seller: String(json.seller),
3285
+ amountUsdc: Number(json.amount) / 10 ** USDC_DECIMALS,
3286
+ escrowUsdc: Number(json.escrow) / 10 ** USDC_DECIMALS,
3287
+ specHash: bytesToHex2(json.spec_hash ?? []),
3288
+ deliverByMs: Number(json.deliver_by_ms),
3289
+ reviewWindowMs: Number(json.review_window_ms),
3290
+ rejectSplitBps: Number(json.reject_split_bps),
3291
+ state,
3292
+ deliveryHash: hasDelivery ? bytesToHex2(deliveryBytes) : null,
3293
+ deliveredAtMs: hasDelivery ? deliveredAtMs : null,
3294
+ createdAtMs: Number(json.created_at_ms)
3295
+ };
3296
+ }
3297
+ function jobActionsFor(job, caller, nowMs = Date.now()) {
3298
+ const me = validateAddress(caller);
3299
+ const isBuyer = me === job.buyer;
3300
+ const isSeller = me === job.seller;
3301
+ const actions = [];
3302
+ if (job.state === "funded") {
3303
+ if (isSeller && nowMs <= job.deliverByMs) actions.push("deliver");
3304
+ if (isBuyer) actions.push("release");
3305
+ if (nowMs > job.deliverByMs) actions.push("refund");
3306
+ } else if (job.state === "delivered") {
3307
+ const windowClosesMs = (job.deliveredAtMs ?? 0) + job.reviewWindowMs;
3308
+ if (isBuyer && nowMs <= windowClosesMs) actions.push("release", "reject");
3309
+ if (nowMs > windowClosesMs) actions.push("release");
3310
+ }
3311
+ return actions;
3312
+ }
3313
+ async function verifyJobForSeller({
3314
+ client,
3315
+ jobId,
3316
+ seller,
3317
+ minAmountUsdc,
3318
+ minRunwayMs = 6e4
3319
+ }) {
3320
+ const job = await getJob(client, jobId);
3321
+ const problems = [];
3322
+ if (job.state !== "funded") {
3323
+ problems.push(`state is "${job.state}", expected "funded"`);
3324
+ }
3325
+ if (job.seller !== validateAddress(seller)) {
3326
+ problems.push(`job pays ${job.seller}, not this seller`);
3327
+ }
3328
+ if (job.escrowUsdc < minAmountUsdc) {
3329
+ problems.push(`escrow holds ${job.escrowUsdc} USDC, price is ${minAmountUsdc}`);
3330
+ }
3331
+ if (job.deliverByMs - Date.now() < minRunwayMs) {
3332
+ problems.push("deadline too close to accept");
3333
+ }
3334
+ return { ok: problems.length === 0, job, problems };
3335
+ }
3336
+
3337
+ // src/index.ts
3134
3338
  init_coinSelection();
3135
3339
 
3136
3340
  // src/composeTx.ts
@@ -3554,6 +3758,7 @@ function displayHandle(label, parentName = AUDRIC_PARENT_NAME) {
3554
3758
  // src/index.ts
3555
3759
  init_preflight();
3556
3760
 
3761
+ exports.A2A_ESCROW_PACKAGE_ID = A2A_ESCROW_PACKAGE_ID;
3557
3762
  exports.AGENT_ID_PARENT = AGENT_ID_PARENT;
3558
3763
  exports.AGENT_ID_PARENT_NAME = AGENT_ID_PARENT_NAME;
3559
3764
  exports.AGENT_ID_PARENT_NFT_ID = AGENT_ID_PARENT_NFT_ID;
@@ -3569,11 +3774,13 @@ exports.GASLESS_MIN_STABLE_AMOUNT = GASLESS_MIN_STABLE_AMOUNT;
3569
3774
  exports.GASLESS_STABLE_TYPES = GASLESS_STABLE_TYPES;
3570
3775
  exports.GAS_RESERVE_MIN = GAS_RESERVE_MIN;
3571
3776
  exports.InvalidAddressError = InvalidAddressError;
3777
+ exports.JOB_STATES = JOB_STATES;
3572
3778
  exports.KNOWN_TARGETS = KNOWN_TARGETS;
3573
3779
  exports.KeypairSigner = KeypairSigner;
3574
3780
  exports.LABEL_PATTERNS = LABEL_PATTERNS;
3575
3781
  exports.LimitEnforcer = LimitEnforcer;
3576
3782
  exports.LimitExceededError = LimitExceededError;
3783
+ exports.MAX_JOB_USDC = MAX_JOB_USDC;
3577
3784
  exports.MIST_PER_SUI = MIST_PER_SUI;
3578
3785
  exports.OPERATION_ASSETS = OPERATION_ASSETS;
3579
3786
  exports.SENDABLE_ASSETS = SENDABLE_ASSETS;
@@ -3597,6 +3804,11 @@ exports.approxUsdValue = approxUsdValue;
3597
3804
  exports.assertAllowedAsset = assertAllowedAsset;
3598
3805
  exports.assertLimitConfig = assertLimitConfig;
3599
3806
  exports.buildAddLeafTx = buildAddLeafTx;
3807
+ exports.buildCreateJobTx = buildCreateJobTx;
3808
+ exports.buildDeliverJobTx = buildDeliverJobTx;
3809
+ exports.buildRefundJobTx = buildRefundJobTx;
3810
+ exports.buildRejectJobTx = buildRejectJobTx;
3811
+ exports.buildReleaseJobTx = buildReleaseJobTx;
3600
3812
  exports.buildRevokeLeafTx = buildRevokeLeafTx;
3601
3813
  exports.buildSendTx = buildSendTx;
3602
3814
  exports.buildSwapTx = buildSwapTx;
@@ -3631,6 +3843,7 @@ exports.getAddress = getAddress;
3631
3843
  exports.getCoinMeta = getCoinMeta;
3632
3844
  exports.getDecimals = getDecimals;
3633
3845
  exports.getDecimalsForCoinType = getDecimalsForCoinType;
3846
+ exports.getJob = getJob;
3634
3847
  exports.getLimits = getLimits;
3635
3848
  exports.getSponsoredSwapProviders = getSponsoredSwapProviders;
3636
3849
  exports.getSuiClient = getSuiClient;
@@ -3640,6 +3853,7 @@ exports.hasLimits = hasLimits;
3640
3853
  exports.isAllowedAsset = isAllowedAsset;
3641
3854
  exports.isCetusRouteFresh = isCetusRouteFresh;
3642
3855
  exports.isInRegistry = isInRegistry;
3856
+ exports.jobActionsFor = jobActionsFor;
3643
3857
  exports.keypairFromPrivateKey = keypairFromPrivateKey;
3644
3858
  exports.listModels = listModels;
3645
3859
  exports.loadKey = loadKey;
@@ -3653,6 +3867,7 @@ exports.normalizeCoinType = normalizeCoinType;
3653
3867
  exports.parseMppSuiChallenge = parseMppSuiChallenge;
3654
3868
  exports.parseSuiRpcTx = parseSuiRpcTx;
3655
3869
  exports.payWithMpp = payWithMpp;
3870
+ exports.preflightCreateJob = preflightCreateJob;
3656
3871
  exports.preflightFail = preflightFail;
3657
3872
  exports.preflightPay = preflightPay;
3658
3873
  exports.preflightSend = preflightSend;
@@ -3684,6 +3899,7 @@ exports.usdcToRaw = usdcToRaw;
3684
3899
  exports.validateAddress = validateAddress;
3685
3900
  exports.validateLabel = validateLabel;
3686
3901
  exports.verifyCetusRouteCoinMatch = verifyCetusRouteCoinMatch;
3902
+ exports.verifyJobForSeller = verifyJobForSeller;
3687
3903
  exports.verifyReceipt = verifyReceipt;
3688
3904
  exports.walletExists = walletExists;
3689
3905
  exports.writeLimitsFile = writeLimitsFile;