@zkp2p/cash 0.1.2 → 0.1.4
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/AGENTS.md +92 -28
- package/README.md +69 -25
- package/dist/chunk-P3KYZ2FX.js +373 -0
- package/dist/{createCashClient-iHuGgjH_.d.cts → createCashClient-BbkfxILl.d.cts} +37 -8
- package/dist/{createCashClient-iHuGgjH_.d.ts → createCashClient-BbkfxILl.d.ts} +37 -8
- package/dist/index.cjs +1099 -254
- package/dist/index.d.cts +1554 -74
- package/dist/index.d.ts +1554 -74
- package/dist/index.js +886 -248
- package/dist/react.cjs +239 -59
- package/dist/react.d.cts +6 -4
- package/dist/react.d.ts +6 -4
- package/dist/react.js +236 -59
- package/dist/tools.cjs +36 -36
- package/dist/tools.d.cts +282 -3
- package/dist/tools.d.ts +282 -3
- package/dist/tools.js +36 -36
- package/docs/lifecycle-and-recovery.md +278 -0
- package/examples/agent-tool-use.ts +122 -0
- package/examples/node-cashout.ts +79 -0
- package/llms.txt +23 -5
- package/package.json +51 -21
- package/skills/peer-cash-integration/SKILL.md +82 -19
- package/dist/chunk-FKVPZVFH.js +0 -188
- package/dist/chunk-FKVPZVFH.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/tools.cjs.map +0 -1
- package/dist/tools.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -237,10 +237,12 @@ function deriveCashOrder(depositId, intents, options = {}) {
|
|
|
237
237
|
const total = options.totalAmount ?? remaining + outstanding + taken + withdrawn;
|
|
238
238
|
const status = options.status;
|
|
239
239
|
const isTerminal = status === "CLOSED" || status === "WITHDRAWN";
|
|
240
|
-
const hasLiveFunds = remaining
|
|
240
|
+
const hasLiveFunds = remaining >= DUST_THRESHOLD || outstanding > 0n;
|
|
241
241
|
let state;
|
|
242
242
|
if (outstanding > 0n) {
|
|
243
243
|
state = taken > 0n ? "delivering" : "matched";
|
|
244
|
+
} else if (!hasLiveFunds && withdrawn > 0n) {
|
|
245
|
+
state = "returned";
|
|
244
246
|
} else if (taken > 0n && !hasLiveFunds) {
|
|
245
247
|
state = "delivered";
|
|
246
248
|
} else if (taken > 0n && hasLiveFunds) {
|
|
@@ -282,7 +284,7 @@ function deriveCashOrder(depositId, intents, options = {}) {
|
|
|
282
284
|
...options.payouts !== void 0 ? { payouts: options.payouts } : {},
|
|
283
285
|
...options.successRateBps !== void 0 ? { successRateBps: options.successRateBps } : {},
|
|
284
286
|
isInFlight,
|
|
285
|
-
withdrawn:
|
|
287
|
+
withdrawn: state === "returned" && withdrawn > 0n
|
|
286
288
|
});
|
|
287
289
|
}
|
|
288
290
|
var ORACLE_KINDS = /* @__PURE__ */ new Set(["oracle_chainlink", "oracle_pyth"]);
|
|
@@ -392,12 +394,14 @@ function resolveCashDepositId(params) {
|
|
|
392
394
|
}
|
|
393
395
|
function parseCompositeDepositId(compositeId) {
|
|
394
396
|
const idx = compositeId.lastIndexOf("_");
|
|
395
|
-
if (idx === -1) {
|
|
396
|
-
return { escrowAddress: "", onchainDepositId: BigInt(compositeId) };
|
|
397
|
-
}
|
|
398
397
|
const escrowAddress = compositeId.slice(0, idx);
|
|
399
|
-
const
|
|
400
|
-
|
|
398
|
+
const rawDepositId = compositeId.slice(idx + 1);
|
|
399
|
+
if (idx <= 0 || compositeId.indexOf("_") !== idx || !viem.isAddress(escrowAddress, { strict: false }) || !/^\d+$/.test(rawDepositId)) {
|
|
400
|
+
throw new Error(`Invalid deposit id: '${compositeId}'`);
|
|
401
|
+
}
|
|
402
|
+
const canonicalEscrowAddress = escrowAddress.toLowerCase();
|
|
403
|
+
const onchainDepositId = BigInt(rawDepositId);
|
|
404
|
+
return { escrowAddress: canonicalEscrowAddress, onchainDepositId };
|
|
401
405
|
}
|
|
402
406
|
var MIN_CASHOUT_AMOUNT = 10000n;
|
|
403
407
|
var RECOMMENDED_MIN_CASHOUT_AMOUNT = 1000000n;
|
|
@@ -415,9 +419,6 @@ var PAYEE_HINTS = {
|
|
|
415
419
|
n26: "MoneyBeam email or phone number"
|
|
416
420
|
};
|
|
417
421
|
var IDENTITY_ATTESTATION_PLATFORMS = /* @__PURE__ */ new Set(["wise", "paypal"]);
|
|
418
|
-
function platformRequiresIdentityAttestation(platform) {
|
|
419
|
-
return IDENTITY_ATTESTATION_PLATFORMS.has(platform);
|
|
420
|
-
}
|
|
421
422
|
function buildCapabilities(environment) {
|
|
422
423
|
const catalog = sdk.getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
|
|
423
424
|
const platforms = Object.entries(catalog).map(([platform, entry]) => {
|
|
@@ -451,12 +452,14 @@ var CashError = class extends Error {
|
|
|
451
452
|
code;
|
|
452
453
|
retryable;
|
|
453
454
|
remediation;
|
|
455
|
+
recovery;
|
|
454
456
|
constructor(shape, options) {
|
|
455
457
|
super(shape.message, options);
|
|
456
458
|
this.name = "CashError";
|
|
457
459
|
this.code = shape.code;
|
|
458
460
|
this.retryable = shape.retryable;
|
|
459
461
|
this.remediation = shape.remediation;
|
|
462
|
+
if (shape.recovery) this.recovery = shape.recovery;
|
|
460
463
|
}
|
|
461
464
|
/** Serializable view (for tool results and logs). */
|
|
462
465
|
toJSON() {
|
|
@@ -464,7 +467,8 @@ var CashError = class extends Error {
|
|
|
464
467
|
code: this.code,
|
|
465
468
|
message: this.message,
|
|
466
469
|
retryable: this.retryable,
|
|
467
|
-
remediation: this.remediation
|
|
470
|
+
remediation: this.remediation,
|
|
471
|
+
...this.recovery ? { recovery: this.recovery } : {}
|
|
468
472
|
};
|
|
469
473
|
}
|
|
470
474
|
};
|
|
@@ -478,18 +482,39 @@ var errors = {
|
|
|
478
482
|
retryable: false,
|
|
479
483
|
remediation: `Pick a currency listed in capabilities() - each one is priced by a live oracle feed.`
|
|
480
484
|
}),
|
|
485
|
+
oracleReadFailed: (currency, cause) => new CashError(
|
|
486
|
+
{
|
|
487
|
+
code: "ORACLE_READ_FAILED",
|
|
488
|
+
message: `The ${currency} market-rate oracle could not be read.`,
|
|
489
|
+
retryable: true,
|
|
490
|
+
remediation: `Retry the estimate shortly or use another healthy Base RPC. Do not present a cached value as a live market rate.`
|
|
491
|
+
},
|
|
492
|
+
{ cause }
|
|
493
|
+
),
|
|
481
494
|
unsupportedPlatform: (platform) => new CashError({
|
|
482
495
|
code: "UNSUPPORTED_PLATFORM",
|
|
483
496
|
message: `'${platform}' is not a supported payout platform in this environment.`,
|
|
484
497
|
retryable: false,
|
|
485
498
|
remediation: `Pick a platform listed in capabilities().`
|
|
486
499
|
}),
|
|
500
|
+
unsupportedPlatformCurrency: (platform, currency) => new CashError({
|
|
501
|
+
code: "UNSUPPORTED_PLATFORM_CURRENCY",
|
|
502
|
+
message: `${platform} cannot receive ${currency} in this environment.`,
|
|
503
|
+
retryable: false,
|
|
504
|
+
remediation: `Pick one of the currencies listed for ${platform} in capabilities().`
|
|
505
|
+
}),
|
|
487
506
|
amountBelowMinimum: (amount, min) => new CashError({
|
|
488
507
|
code: "AMOUNT_BELOW_MINIMUM",
|
|
489
508
|
message: `Amount ${amount} is below the minimum cash-out of ${min} USDC base units.`,
|
|
490
509
|
retryable: false,
|
|
491
510
|
remediation: `Increase the amount to at least ${min} base units (${Number(min) / 1e6} USDC).`
|
|
492
511
|
}),
|
|
512
|
+
invalidIntentAmountRange: (amount, min, max) => new CashError({
|
|
513
|
+
code: "INVALID_INTENT_AMOUNT_RANGE",
|
|
514
|
+
message: `Intent amount range ${min}-${max} is invalid for a ${amount} base-unit cash-out.`,
|
|
515
|
+
retryable: false,
|
|
516
|
+
remediation: `Use a positive minimum no greater than the maximum, and a maximum no greater than the cash-out amount.`
|
|
517
|
+
}),
|
|
493
518
|
activeIntentBlocksWithdrawal: (depositId) => new CashError({
|
|
494
519
|
code: "ACTIVE_INTENT_BLOCKS_WITHDRAWAL",
|
|
495
520
|
message: `Order ${depositId} has a live buyer intent; escrow blocks withdrawal while a buyer may still deliver.`,
|
|
@@ -502,12 +527,27 @@ var errors = {
|
|
|
502
527
|
retryable: true,
|
|
503
528
|
remediation: `Withdraw at most the available (unlocked) amount, or omit the amount to close the order fully once no buyer intent is live.`
|
|
504
529
|
}),
|
|
530
|
+
insufficientTokenBalance: (requiredAmount) => new CashError({
|
|
531
|
+
code: "INSUFFICIENT_TOKEN_BALANCE",
|
|
532
|
+
message: requiredAmount === void 0 ? `The wallet does not hold enough of the source token for this transaction.` : `The wallet does not hold the ${requiredAmount} base units required for this transaction.`,
|
|
533
|
+
retryable: false,
|
|
534
|
+
remediation: requiredAmount === void 0 ? `Fund the wallet with the required token amount, then retry.` : `Fund the wallet to at least ${requiredAmount} token base units, then retry.`
|
|
535
|
+
}),
|
|
505
536
|
orderNotActive: (depositId) => new CashError({
|
|
506
537
|
code: "ORDER_NOT_ACTIVE",
|
|
507
538
|
message: `Order ${depositId} is closed (delivered or returned); it cannot be topped up.`,
|
|
508
539
|
retryable: false,
|
|
509
540
|
remediation: `Start a new cash-out with cashout() instead.`
|
|
510
541
|
}),
|
|
542
|
+
invalidDepositId: (depositId, cause) => new CashError(
|
|
543
|
+
{
|
|
544
|
+
code: "INVALID_DEPOSIT_ID",
|
|
545
|
+
message: `'${depositId}' is not a valid Peer Cash deposit id.`,
|
|
546
|
+
retryable: false,
|
|
547
|
+
remediation: `Use the depositId returned by cashout() (escrowAddress_onchainDepositId) without modifying it.`
|
|
548
|
+
},
|
|
549
|
+
{ cause }
|
|
550
|
+
),
|
|
511
551
|
nothingToWithdraw: (depositId) => new CashError({
|
|
512
552
|
code: "NOTHING_TO_WITHDRAW",
|
|
513
553
|
message: `Order ${depositId} holds no withdrawable funds (already delivered or returned).`,
|
|
@@ -526,6 +566,15 @@ var errors = {
|
|
|
526
566
|
retryable: true,
|
|
527
567
|
remediation: `Verify the composite depositId (escrow_onchainId). If the deposit was created seconds ago this is indexer lag - retry shortly.`
|
|
528
568
|
}),
|
|
569
|
+
indexerUnavailable: (operation, cause) => new CashError(
|
|
570
|
+
{
|
|
571
|
+
code: "INDEXER_UNAVAILABLE",
|
|
572
|
+
message: `The protocol indexer could not complete the ${operation} query.`,
|
|
573
|
+
retryable: true,
|
|
574
|
+
remediation: `Retry shortly. Keep the composite depositId or owner address so the read can resume without repeating an on-chain transaction.`
|
|
575
|
+
},
|
|
576
|
+
{ cause }
|
|
577
|
+
),
|
|
529
578
|
payeeRegistrationFailed: (cause) => new CashError(
|
|
530
579
|
{
|
|
531
580
|
code: "PAYEE_REGISTRATION_FAILED",
|
|
@@ -556,12 +605,109 @@ var errors = {
|
|
|
556
605
|
retryable: false,
|
|
557
606
|
remediation: `For one-call source cashout, deliver Relay output to the depositor address. For a different recipient, bridge first and then cash out from that recipient's signer.`
|
|
558
607
|
}),
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
608
|
+
sourceCapabilitiesFailed: (cause) => new CashError(
|
|
609
|
+
{
|
|
610
|
+
code: "SOURCE_CAPABILITIES_FAILED",
|
|
611
|
+
message: `Relay source-chain discovery failed.`,
|
|
612
|
+
retryable: true,
|
|
613
|
+
remediation: `Retry sourceCapabilities() shortly, or use the default Base USDC path.`
|
|
614
|
+
},
|
|
615
|
+
{ cause }
|
|
616
|
+
),
|
|
617
|
+
sourceQuoteFailed: (cause) => new CashError(
|
|
618
|
+
{
|
|
619
|
+
code: "SOURCE_QUOTE_FAILED",
|
|
620
|
+
message: `Relay did not return a valid route to canonical Base USDC.`,
|
|
621
|
+
retryable: true,
|
|
622
|
+
remediation: `Refresh source capabilities and request a new quote. Do not submit transactions from this response.`
|
|
623
|
+
},
|
|
624
|
+
{ cause }
|
|
625
|
+
),
|
|
626
|
+
sourceExecutionFailed: (cause, evidence) => new CashError(
|
|
627
|
+
{
|
|
628
|
+
code: "SOURCE_EXECUTION_FAILED",
|
|
629
|
+
message: `Relay source-route execution did not complete successfully.`,
|
|
630
|
+
retryable: false,
|
|
631
|
+
remediation: `Inspect the wallet transactions and Relay request status before retrying so the source transfer is never submitted twice.`,
|
|
632
|
+
...evidence && (evidence.requestId !== void 0 || evidence.txHashes.length > 0) ? {
|
|
633
|
+
recovery: {
|
|
634
|
+
kind: "inspect-relay-route",
|
|
635
|
+
...evidence.requestId ? { requestId: evidence.requestId } : {},
|
|
636
|
+
txHashes: evidence.txHashes,
|
|
637
|
+
...evidence.transactions ? { transactions: evidence.transactions } : {}
|
|
638
|
+
}
|
|
639
|
+
} : {}
|
|
640
|
+
},
|
|
641
|
+
{ cause }
|
|
642
|
+
),
|
|
643
|
+
sourceStatusFailed: (requestId, cause) => new CashError(
|
|
644
|
+
{
|
|
645
|
+
code: "SOURCE_STATUS_FAILED",
|
|
646
|
+
message: `Relay status is unavailable for request ${requestId}.`,
|
|
647
|
+
retryable: true,
|
|
648
|
+
remediation: `Retry relayStatus(requestId) shortly; keep the request id and transaction hashes for recovery.`
|
|
649
|
+
},
|
|
650
|
+
{ cause }
|
|
651
|
+
),
|
|
652
|
+
sourceRouteCompletedCashoutFailed: (source, cause) => new CashError(
|
|
653
|
+
{
|
|
654
|
+
code: "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED",
|
|
655
|
+
message: `Relay completed, but the Base USDC cash-out transaction was not created.`,
|
|
656
|
+
retryable: false,
|
|
657
|
+
remediation: `Do not repeat the Relay route. Retry cashout() without source using the recovery amount already delivered on Base.`,
|
|
658
|
+
recovery: {
|
|
659
|
+
kind: "retry-base-usdc-cashout",
|
|
660
|
+
amount: source.amount.toString(),
|
|
661
|
+
...source.requestId ? { requestId: source.requestId } : {},
|
|
662
|
+
txHashes: source.txHashes,
|
|
663
|
+
...source.transactions ? { transactions: source.transactions } : {}
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
{ cause }
|
|
667
|
+
),
|
|
668
|
+
sourceCashoutSubmissionUnknown: (source, depositor, cause) => new CashError(
|
|
669
|
+
{
|
|
670
|
+
code: "SOURCE_CASHOUT_SUBMISSION_UNKNOWN",
|
|
671
|
+
message: `Relay completed, but the Base cash-out submission did not return a transaction hash.`,
|
|
672
|
+
retryable: false,
|
|
673
|
+
remediation: `Do not repeat Relay or submit another cash-out yet. Inspect recent Base transactions and orders(${depositor}) to prove no deposit was broadcast; only then retry Base-USDC-only with the recovery amount.`,
|
|
674
|
+
recovery: {
|
|
675
|
+
kind: "inspect-base-cashout-submission",
|
|
676
|
+
amount: source.amount.toString(),
|
|
677
|
+
...source.requestId ? { requestId: source.requestId } : {},
|
|
678
|
+
txHashes: source.txHashes,
|
|
679
|
+
...source.transactions ? { transactions: source.transactions } : {},
|
|
680
|
+
depositor
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
{ cause }
|
|
684
|
+
),
|
|
685
|
+
sourceCashoutStatusUnknown: (source, depositTxHash, cause) => new CashError(
|
|
686
|
+
{
|
|
687
|
+
code: "SOURCE_CASHOUT_STATUS_UNKNOWN",
|
|
688
|
+
message: `Relay completed and Base cash-out transaction ${depositTxHash} was submitted, but its receipt could not be confirmed.`,
|
|
689
|
+
retryable: false,
|
|
690
|
+
remediation: `Do not repeat the Relay route or submit another cash-out. Inspect the Base transaction; if it succeeded, recover the depositId from its DepositReceived log, and if it reverted, retry a Base-USDC-only cashout with the recovery amount.`,
|
|
691
|
+
recovery: {
|
|
692
|
+
kind: "inspect-base-cashout-transaction",
|
|
693
|
+
amount: source.amount.toString(),
|
|
694
|
+
...source.requestId ? { requestId: source.requestId } : {},
|
|
695
|
+
txHashes: source.txHashes,
|
|
696
|
+
...source.transactions ? { transactions: source.transactions } : {},
|
|
697
|
+
depositTxHash
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
{ cause }
|
|
701
|
+
),
|
|
702
|
+
allowanceNotVisible: (amount, cause) => new CashError(
|
|
703
|
+
{
|
|
704
|
+
code: "ALLOWANCE_NOT_VISIBLE",
|
|
705
|
+
message: `USDC approval for ${amount} base units did not become visible on the read path in time.`,
|
|
706
|
+
retryable: true,
|
|
707
|
+
remediation: `The approve transaction mined but the RPC read path is stale or unavailable. Retry the same call in a few seconds.`
|
|
708
|
+
},
|
|
709
|
+
{ cause }
|
|
710
|
+
),
|
|
565
711
|
depositResolutionFailed: (txHash) => new CashError({
|
|
566
712
|
code: "DEPOSIT_RESOLUTION_FAILED",
|
|
567
713
|
message: `Deposit transaction ${txHash} succeeded but no DepositReceived event was found in the receipt.`,
|
|
@@ -574,6 +720,21 @@ var errors = {
|
|
|
574
720
|
retryable: false,
|
|
575
721
|
remediation: `Pass { signer } (a viem WalletClient with an account), or use prepare() and submit the returned txs with your own signing infrastructure.`
|
|
576
722
|
}),
|
|
723
|
+
signerChainMismatch: (verb, expectedChainId, actualChainId) => new CashError({
|
|
724
|
+
code: "SIGNER_CHAIN_MISMATCH",
|
|
725
|
+
message: `${verb} requires chain ${expectedChainId}, but the signer is connected to chain ${actualChainId}.`,
|
|
726
|
+
retryable: false,
|
|
727
|
+
remediation: `Switch the wallet to chain ${expectedChainId}, obtain a fresh quote if Relay is involved, and retry before submitting any transaction.`
|
|
728
|
+
}),
|
|
729
|
+
signerChainUnavailable: (verb, expectedChainId, cause) => new CashError(
|
|
730
|
+
{
|
|
731
|
+
code: "SIGNER_CHAIN_UNAVAILABLE",
|
|
732
|
+
message: `${verb} could not verify that the signer is connected to chain ${expectedChainId}.`,
|
|
733
|
+
retryable: true,
|
|
734
|
+
remediation: `Reconnect the wallet, switch it to chain ${expectedChainId}, and retry before submitting any transaction.`
|
|
735
|
+
},
|
|
736
|
+
{ cause }
|
|
737
|
+
),
|
|
577
738
|
watchTimeout: (depositId, timeoutMs) => new CashError({
|
|
578
739
|
code: "WATCH_TIMEOUT",
|
|
579
740
|
message: `watch(${depositId}) exceeded ${timeoutMs}ms without reaching a terminal state.`,
|
|
@@ -589,6 +750,30 @@ var errors = {
|
|
|
589
750
|
},
|
|
590
751
|
{ cause }
|
|
591
752
|
),
|
|
753
|
+
transactionSubmissionUnknown: (operation, cause, recovery) => new CashError(
|
|
754
|
+
{
|
|
755
|
+
code: "TRANSACTION_SUBMISSION_UNKNOWN",
|
|
756
|
+
message: `The Base ${operation} submission did not return a transaction hash.`,
|
|
757
|
+
retryable: false,
|
|
758
|
+
remediation: `Do not submit the operation again until you inspect recent Base wallet activity and protocol state; the first transaction may already exist.`,
|
|
759
|
+
...recovery ? { recovery } : {}
|
|
760
|
+
},
|
|
761
|
+
{ cause }
|
|
762
|
+
),
|
|
763
|
+
transactionStatusUnknown: (txHash, cause, operation = "transaction") => new CashError(
|
|
764
|
+
{
|
|
765
|
+
code: "TRANSACTION_STATUS_UNKNOWN",
|
|
766
|
+
message: `Transaction ${txHash} was submitted, but its receipt could not be confirmed.`,
|
|
767
|
+
retryable: false,
|
|
768
|
+
remediation: `Do not resubmit the operation until you inspect ${txHash} on Base or successfully fetch its receipt; the transaction may already have succeeded.`,
|
|
769
|
+
recovery: {
|
|
770
|
+
kind: "inspect-base-transaction",
|
|
771
|
+
transactionHash: txHash,
|
|
772
|
+
operation
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
{ cause }
|
|
776
|
+
),
|
|
592
777
|
escrowPaused: () => new CashError({
|
|
593
778
|
code: "ESCROW_PAUSED",
|
|
594
779
|
message: `The escrow contract is paused; deposits are temporarily disabled.`,
|
|
@@ -606,18 +791,22 @@ var errors = {
|
|
|
606
791
|
{ cause }
|
|
607
792
|
)
|
|
608
793
|
};
|
|
609
|
-
function mapChainError(verb, err) {
|
|
794
|
+
function mapChainError(verb, err, context = {}) {
|
|
610
795
|
if (isCashError(err)) return err;
|
|
611
796
|
const message = err instanceof Error ? err.message : String(err);
|
|
612
797
|
if (/\bpaused\b/i.test(message)) return errors.escrowPaused();
|
|
613
|
-
if (/exceeds
|
|
614
|
-
return errors.
|
|
798
|
+
if (/exceeds balance|insufficient token balance/i.test(message)) {
|
|
799
|
+
return errors.insufficientTokenBalance(context.requiredAmount);
|
|
800
|
+
}
|
|
801
|
+
if (/exceeds allowance|insufficient allowance/i.test(message)) {
|
|
802
|
+
return errors.allowanceNotVisible(context.requiredAmount ?? 0n);
|
|
615
803
|
}
|
|
616
804
|
return errors.chainCallFailed(verb, err);
|
|
617
805
|
}
|
|
618
|
-
var ETA_WINDOW_DAYS =
|
|
806
|
+
var ETA_WINDOW_DAYS = 30;
|
|
619
807
|
var ETA_WINDOW_SECONDS = ETA_WINDOW_DAYS * 24 * 60 * 60;
|
|
620
|
-
var
|
|
808
|
+
var ETA_PAGE_LIMIT = 250;
|
|
809
|
+
var ETA_MAX_DEPOSIT_SCAN = 2e3;
|
|
621
810
|
var FULFILLED = /* @__PURE__ */ new Set(["FULFILLED", "MANUALLY_RELEASED"]);
|
|
622
811
|
function toUnixSeconds2(value) {
|
|
623
812
|
if (value === null || value === void 0 || value === "") return void 0;
|
|
@@ -652,19 +841,27 @@ function matchesPayout(deposit, environment, platform, currency) {
|
|
|
652
841
|
deposit.currencies ?? [],
|
|
653
842
|
sdk.getPaymentMethodsCatalog(BASE_CHAIN_ID, environment)
|
|
654
843
|
);
|
|
655
|
-
if (payouts.length === 0) return true;
|
|
656
844
|
return payouts.some(
|
|
657
|
-
(payout) => (platform === void 0 || payout.platform === platform) && (currency === void 0 || payout.currency === currency)
|
|
845
|
+
(payout) => payout.pricing.marketRate && payout.pricing.spreadBps === 0 && (platform === void 0 || payout.platform === platform) && (currency === void 0 || payout.currency === currency)
|
|
658
846
|
);
|
|
659
847
|
}
|
|
660
848
|
async function readFillEta(client, input) {
|
|
661
849
|
const now = Math.floor(Date.now() / 1e3);
|
|
662
850
|
const windowStart = now - ETA_WINDOW_SECONDS;
|
|
663
|
-
const deposits =
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
851
|
+
const deposits = [];
|
|
852
|
+
for (let offset = 0; offset < ETA_MAX_DEPOSIT_SCAN; offset += ETA_PAGE_LIMIT) {
|
|
853
|
+
const page = await client.indexer.getDepositsWithRelations(
|
|
854
|
+
{ chainId: BASE_CHAIN_ID },
|
|
855
|
+
{ limit: ETA_PAGE_LIMIT, offset, orderBy: "timestamp", orderDirection: "desc" },
|
|
856
|
+
{ includeIntents: true, intentStatuses: ["FULFILLED", "MANUALLY_RELEASED"] }
|
|
857
|
+
);
|
|
858
|
+
deposits.push(...page);
|
|
859
|
+
if (page.length < ETA_PAGE_LIMIT) break;
|
|
860
|
+
const oldestCreatedAt = Math.min(
|
|
861
|
+
...page.map((deposit) => toUnixSeconds2(deposit.createdAt ?? deposit.timestamp) ?? Infinity)
|
|
862
|
+
);
|
|
863
|
+
if (oldestCreatedAt < windowStart) break;
|
|
864
|
+
}
|
|
668
865
|
const firstFillLatencies = [];
|
|
669
866
|
for (const deposit of deposits) {
|
|
670
867
|
const createdAt = toUnixSeconds2(deposit.createdAt ?? deposit.timestamp);
|
|
@@ -768,20 +965,175 @@ function normalizeChain(chain) {
|
|
|
768
965
|
function isSupportedEvmChain(chain) {
|
|
769
966
|
return chain.vmType === void 0 || chain.vmType === "evm";
|
|
770
967
|
}
|
|
968
|
+
function isExecutableSourceChain(chain) {
|
|
969
|
+
return isSupportedEvmChain(chain) && !chain.disabled && chain.depositEnabled && !chain.blockProductionLagging;
|
|
970
|
+
}
|
|
771
971
|
function quoteRequestId(quote) {
|
|
772
972
|
return quote.steps.map((step) => step.requestId).find((id) => id !== void 0);
|
|
773
973
|
}
|
|
974
|
+
function collectRelayTransactions(steps, sourceChainId) {
|
|
975
|
+
const origin = [];
|
|
976
|
+
const destination = [];
|
|
977
|
+
const record = (tx) => {
|
|
978
|
+
(tx.chainId === sourceChainId ? origin : destination).push(tx);
|
|
979
|
+
};
|
|
980
|
+
for (const step of steps) {
|
|
981
|
+
for (const item of step.items) {
|
|
982
|
+
for (const tx of item.internalTxHashes ?? []) {
|
|
983
|
+
record({ hash: tx.txHash, chainId: tx.chainId });
|
|
984
|
+
}
|
|
985
|
+
for (const tx of item.txHashes ?? []) {
|
|
986
|
+
record({ hash: tx.txHash, chainId: tx.chainId });
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const dedupe = (txs) => [
|
|
991
|
+
...new Map(txs.map((tx) => [`${tx.chainId}:${tx.hash.toLowerCase()}`, tx])).values()
|
|
992
|
+
];
|
|
993
|
+
return { origin: dedupe(origin), destination: dedupe(destination) };
|
|
994
|
+
}
|
|
995
|
+
function relayTransactionHashes(transactions) {
|
|
996
|
+
return [
|
|
997
|
+
...new Set([...transactions.origin, ...transactions.destination].map(({ hash }) => hash))
|
|
998
|
+
];
|
|
999
|
+
}
|
|
774
1000
|
function quoteSourceChainId(quote) {
|
|
775
1001
|
const details = asRecord(quote.details);
|
|
776
1002
|
const currencyIn = asRecord(details.currencyIn);
|
|
777
1003
|
const sourceCurrency = asRecord(currencyIn.currency);
|
|
778
1004
|
return asNumber(sourceCurrency.chainId);
|
|
779
1005
|
}
|
|
1006
|
+
function assertCanonicalRelayDestination(quote) {
|
|
1007
|
+
const details = asRecord(quote.details);
|
|
1008
|
+
const currencyOut = asRecord(details.currencyOut);
|
|
1009
|
+
const destination = asRecord(currencyOut.currency);
|
|
1010
|
+
if (asNumber(destination.chainId) !== BASE_CHAIN_ID || asString(destination.address)?.toLowerCase() !== BASE_USDC_ADDRESS.toLowerCase()) {
|
|
1011
|
+
throw new Error("Relay quote destination is not canonical Base USDC");
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
async function assertWalletChainId(wallet, expectedChainId, operation) {
|
|
1015
|
+
let actualChainId;
|
|
1016
|
+
try {
|
|
1017
|
+
actualChainId = await wallet.getChainId();
|
|
1018
|
+
} catch (err) {
|
|
1019
|
+
throw errors.signerChainUnavailable(operation, expectedChainId, err);
|
|
1020
|
+
}
|
|
1021
|
+
if (actualChainId !== expectedChainId) {
|
|
1022
|
+
throw errors.signerChainMismatch(operation, expectedChainId, actualChainId);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
async function assertRelayExecutionIdentity(quote, wallet, expectedRecipient) {
|
|
1026
|
+
const signer = wallet.account?.address;
|
|
1027
|
+
if (!signer) throw new Error("Relay execution requires a wallet account");
|
|
1028
|
+
const sourceChainId = quoteSourceChainId(quote);
|
|
1029
|
+
if (sourceChainId !== void 0) {
|
|
1030
|
+
await assertWalletChainId(wallet, sourceChainId, "Relay execution");
|
|
1031
|
+
}
|
|
1032
|
+
const details = asRecord(quote.details);
|
|
1033
|
+
const sender = asString(details.sender);
|
|
1034
|
+
const recipient = asString(details.recipient);
|
|
1035
|
+
if (!sender || sender.toLowerCase() !== signer.toLowerCase()) {
|
|
1036
|
+
throw new Error("Relay quote sender does not match the execution signer");
|
|
1037
|
+
}
|
|
1038
|
+
const destinationOwner = expectedRecipient ?? signer;
|
|
1039
|
+
if (!recipient || recipient.toLowerCase() !== destinationOwner.toLowerCase()) {
|
|
1040
|
+
throw new Error("Relay quote recipient does not match the expected Base recipient");
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
function isRelaySecretKey(key) {
|
|
1044
|
+
const normalized = key.toLowerCase();
|
|
1045
|
+
return normalized === "headers" || normalized === "apikey";
|
|
1046
|
+
}
|
|
1047
|
+
function redactRelayValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
1048
|
+
if (value === null || typeof value !== "object") return value;
|
|
1049
|
+
if (value instanceof Date || value instanceof Error) return value;
|
|
1050
|
+
const existing = seen.get(value);
|
|
1051
|
+
if (existing !== void 0) return existing;
|
|
1052
|
+
if (Array.isArray(value)) {
|
|
1053
|
+
const output2 = [];
|
|
1054
|
+
seen.set(value, output2);
|
|
1055
|
+
for (const entry of value) output2.push(redactRelayValue(entry, seen));
|
|
1056
|
+
return output2;
|
|
1057
|
+
}
|
|
1058
|
+
const output = {};
|
|
1059
|
+
seen.set(value, output);
|
|
1060
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1061
|
+
if (!isRelaySecretKey(key)) output[key] = redactRelayValue(entry, seen);
|
|
1062
|
+
}
|
|
1063
|
+
return output;
|
|
1064
|
+
}
|
|
1065
|
+
var RELAY_WIRE_TYPE = "__zkp2pCashType";
|
|
1066
|
+
function sanitizeRelayValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1067
|
+
if (typeof value === "bigint") {
|
|
1068
|
+
return { [RELAY_WIRE_TYPE]: "bigint", value: value.toString() };
|
|
1069
|
+
}
|
|
1070
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
1071
|
+
return value;
|
|
1072
|
+
}
|
|
1073
|
+
if (typeof value === "number") {
|
|
1074
|
+
return Number.isFinite(value) ? value : { [RELAY_WIRE_TYPE]: "number", value: String(value) };
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof value === "undefined") return { [RELAY_WIRE_TYPE]: "undefined" };
|
|
1077
|
+
if (value instanceof Date) {
|
|
1078
|
+
return { [RELAY_WIRE_TYPE]: "date", value: value.toISOString() };
|
|
1079
|
+
}
|
|
1080
|
+
if (value instanceof Error) {
|
|
1081
|
+
return {
|
|
1082
|
+
[RELAY_WIRE_TYPE]: "error",
|
|
1083
|
+
name: value.name,
|
|
1084
|
+
message: value.message
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
if (typeof value !== "object") return void 0;
|
|
1088
|
+
if (seen.has(value)) throw new TypeError("Relay payload contains a circular reference");
|
|
1089
|
+
seen.add(value);
|
|
1090
|
+
if (Array.isArray(value)) {
|
|
1091
|
+
const output2 = value.map((entry) => sanitizeRelayValue(entry, seen));
|
|
1092
|
+
seen.delete(value);
|
|
1093
|
+
return output2;
|
|
1094
|
+
}
|
|
1095
|
+
const output = {};
|
|
1096
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1097
|
+
if (isRelaySecretKey(key)) continue;
|
|
1098
|
+
const sanitized = sanitizeRelayValue(entry, seen);
|
|
1099
|
+
if (sanitized !== void 0) output[key] = sanitized;
|
|
1100
|
+
}
|
|
1101
|
+
seen.delete(value);
|
|
1102
|
+
return output;
|
|
1103
|
+
}
|
|
1104
|
+
function restoreRelayValue(value) {
|
|
1105
|
+
if (Array.isArray(value)) return value.map(restoreRelayValue);
|
|
1106
|
+
if (value === null || typeof value !== "object") return value;
|
|
1107
|
+
const row = value;
|
|
1108
|
+
const wireType = row[RELAY_WIRE_TYPE];
|
|
1109
|
+
const keyCount = Object.keys(row).length;
|
|
1110
|
+
if (keyCount === 2 && wireType === "bigint" && typeof row.value === "string") {
|
|
1111
|
+
return BigInt(row.value);
|
|
1112
|
+
}
|
|
1113
|
+
if (keyCount === 2 && wireType === "date" && typeof row.value === "string") {
|
|
1114
|
+
return new Date(row.value);
|
|
1115
|
+
}
|
|
1116
|
+
if (keyCount === 2 && wireType === "number" && typeof row.value === "string") {
|
|
1117
|
+
return Number(row.value);
|
|
1118
|
+
}
|
|
1119
|
+
if (keyCount === 1 && wireType === "undefined") return void 0;
|
|
1120
|
+
if (keyCount === 3 && wireType === "error" && typeof row.message === "string") {
|
|
1121
|
+
const error = new Error(row.message);
|
|
1122
|
+
if (typeof row.name === "string") error.name = row.name;
|
|
1123
|
+
return error;
|
|
1124
|
+
}
|
|
1125
|
+
return Object.fromEntries(
|
|
1126
|
+
Object.entries(row).map(([key, entry]) => [key, restoreRelayValue(entry)])
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
function redactRelayQuoteRaw(quote) {
|
|
1130
|
+
return redactRelayValue(quote);
|
|
1131
|
+
}
|
|
780
1132
|
function sanitizeRelayQuoteRaw(quote) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
return
|
|
1133
|
+
return sanitizeRelayValue(quote);
|
|
1134
|
+
}
|
|
1135
|
+
function restoreRelayQuoteRaw(value) {
|
|
1136
|
+
return restoreRelayValue(value);
|
|
785
1137
|
}
|
|
786
1138
|
async function resolveRelayChains(options, client, config = {}) {
|
|
787
1139
|
const preferInjectedClientChains = config.preferInjectedClientChains ?? true;
|
|
@@ -795,19 +1147,38 @@ function relayQuoteFromExecute(input, quote) {
|
|
|
795
1147
|
const currencyOut = asRecord(details.currencyOut);
|
|
796
1148
|
const sourceCurrency = asRecord(currencyIn.currency);
|
|
797
1149
|
const destinationCurrency = asRecord(currencyOut.currency);
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
const
|
|
1150
|
+
const sourceChainId = asNumber(sourceCurrency.chainId);
|
|
1151
|
+
const sourceAddress = asString(sourceCurrency.address);
|
|
1152
|
+
const sender = asString(details.sender);
|
|
1153
|
+
const recipient = asString(details.recipient);
|
|
1154
|
+
const expectedRecipient = input.recipient ?? input.user;
|
|
1155
|
+
const destinationChainId = asNumber(destinationCurrency.chainId);
|
|
1156
|
+
const destinationAddress = asString(destinationCurrency.address);
|
|
1157
|
+
if (sourceChainId !== input.source.chainId || sourceAddress?.toLowerCase() !== input.source.currency.toLowerCase()) {
|
|
1158
|
+
throw new Error("Relay quote source does not match the requested asset");
|
|
1159
|
+
}
|
|
1160
|
+
if (!sender || sender.toLowerCase() !== input.user.toLowerCase()) {
|
|
1161
|
+
throw new Error("Relay quote sender does not match the requested wallet");
|
|
1162
|
+
}
|
|
1163
|
+
if (!recipient || recipient.toLowerCase() !== expectedRecipient.toLowerCase()) {
|
|
1164
|
+
throw new Error("Relay quote recipient does not match the requested Base recipient");
|
|
1165
|
+
}
|
|
1166
|
+
if (destinationChainId !== BASE_CHAIN_ID || destinationAddress?.toLowerCase() !== BASE_USDC_ADDRESS.toLowerCase()) {
|
|
1167
|
+
throw new Error("Relay quote destination is not canonical Base USDC");
|
|
1168
|
+
}
|
|
1169
|
+
const source = normalizeToken(input.source.chainId, sourceCurrency);
|
|
1170
|
+
if (!source) throw new Error("Relay quote source metadata is malformed");
|
|
1171
|
+
const destination = normalizeToken(destinationChainId, destinationCurrency);
|
|
1172
|
+
if (!destination) throw new Error("Relay quote destination metadata is malformed");
|
|
805
1173
|
const txs = quote.steps.flatMap(
|
|
806
1174
|
(step) => step.items.map((item) => normalizeTx(item.data, input.source.chainId)).filter((tx) => tx !== null)
|
|
807
1175
|
);
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
1176
|
+
const rawOutputAmount = currencyOut.minimumAmount ?? currencyOut.amount;
|
|
1177
|
+
if (rawOutputAmount === void 0 || rawOutputAmount === null) {
|
|
1178
|
+
throw new Error("Relay quote is missing an output amount");
|
|
1179
|
+
}
|
|
1180
|
+
const outputAmount = BigInt(String(rawOutputAmount));
|
|
1181
|
+
if (outputAmount <= 0n) throw new Error("Relay quote output amount must be positive");
|
|
811
1182
|
const requestId = quoteRequestId(quote);
|
|
812
1183
|
const rate = asNumber(details.rate);
|
|
813
1184
|
const timeEstimateSeconds = asNumber(details.timeEstimate);
|
|
@@ -815,92 +1186,135 @@ function relayQuoteFromExecute(input, quote) {
|
|
|
815
1186
|
...requestId ? { requestId } : {},
|
|
816
1187
|
source,
|
|
817
1188
|
destination,
|
|
818
|
-
inputAmount: BigInt(String(currencyIn.amount
|
|
1189
|
+
inputAmount: BigInt(String(currencyIn.amount)),
|
|
819
1190
|
outputAmount,
|
|
820
1191
|
...rate !== void 0 ? { rate } : {},
|
|
821
1192
|
...timeEstimateSeconds !== void 0 ? { timeEstimateSeconds } : {},
|
|
822
1193
|
...quote.fees !== void 0 ? { fees: quote.fees } : {},
|
|
823
1194
|
txs,
|
|
824
|
-
raw:
|
|
1195
|
+
raw: redactRelayQuoteRaw(quote)
|
|
825
1196
|
};
|
|
826
1197
|
}
|
|
827
1198
|
async function readRelaySourceCapabilities(options = {}) {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1199
|
+
try {
|
|
1200
|
+
const client = relayClient(options);
|
|
1201
|
+
const chains = await resolveRelayChains(options, client);
|
|
1202
|
+
return {
|
|
1203
|
+
destination: BASE_USDC_ASSET,
|
|
1204
|
+
chains: chains.map(normalizeChain).filter((chain) => chain.tokens.length > 0 && isExecutableSourceChain(chain)).sort((a, b) => a.displayName.localeCompare(b.displayName)),
|
|
1205
|
+
source: "relay-sdk",
|
|
1206
|
+
asOf: Math.floor(Date.now() / 1e3)
|
|
1207
|
+
};
|
|
1208
|
+
} catch (err) {
|
|
1209
|
+
if (isCashError(err)) throw err;
|
|
1210
|
+
throw errors.sourceCapabilitiesFailed(err);
|
|
1211
|
+
}
|
|
836
1212
|
}
|
|
837
1213
|
async function quoteRelayToBaseUsdc(input, options = {}) {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1214
|
+
try {
|
|
1215
|
+
if (input.amount <= 0n) throw new Error("Relay quote amount must be positive");
|
|
1216
|
+
const client = relayClient(options);
|
|
1217
|
+
const quote = await client.actions.getQuote(
|
|
1218
|
+
{
|
|
1219
|
+
chainId: input.source.chainId,
|
|
1220
|
+
currency: input.source.currency,
|
|
1221
|
+
toChainId: BASE_CHAIN_ID,
|
|
1222
|
+
toCurrency: BASE_USDC_ADDRESS,
|
|
1223
|
+
user: input.user,
|
|
1224
|
+
recipient: input.recipient ?? input.user,
|
|
1225
|
+
amount: input.amount.toString(),
|
|
1226
|
+
tradeType: input.tradeType ?? "EXACT_INPUT"
|
|
1227
|
+
},
|
|
1228
|
+
false
|
|
1229
|
+
);
|
|
1230
|
+
return relayQuoteFromExecute(input, quote);
|
|
1231
|
+
} catch (err) {
|
|
1232
|
+
if (isCashError(err)) throw err;
|
|
1233
|
+
throw errors.sourceQuoteFailed(err);
|
|
1234
|
+
}
|
|
853
1235
|
}
|
|
854
1236
|
async function executeRelayQuote(quote, wallet, options = {}) {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1237
|
+
let observedRequestId;
|
|
1238
|
+
let observedTransactions = { origin: [], destination: [] };
|
|
1239
|
+
try {
|
|
1240
|
+
const rawQuote = "raw" in quote ? quote.raw : quote;
|
|
1241
|
+
observedRequestId = quoteRequestId(rawQuote);
|
|
1242
|
+
assertCanonicalRelayDestination(rawQuote);
|
|
1243
|
+
await assertRelayExecutionIdentity(rawQuote, wallet, options.recipient);
|
|
1244
|
+
const client = relayClient(options.relay);
|
|
1245
|
+
const sourceChainId = quoteSourceChainId(rawQuote);
|
|
1246
|
+
if (sourceChainId !== void 0 && !(client.chains ?? []).some((chain) => chain.id === sourceChainId)) {
|
|
1247
|
+
await resolveRelayChains(options.relay ?? {}, client, { preferInjectedClientChains: false });
|
|
1248
|
+
}
|
|
1249
|
+
const onProgress = (data2) => {
|
|
1250
|
+
const progressSteps = Array.isArray(data2.steps) ? data2.steps : [];
|
|
1251
|
+
observedRequestId = progressSteps.map((step) => step.requestId).find((id) => id !== void 0) ?? observedRequestId;
|
|
1252
|
+
observedTransactions = collectRelayTransactions(progressSteps, sourceChainId);
|
|
1253
|
+
if (options.onProgress) {
|
|
1254
|
+
try {
|
|
1255
|
+
options.onProgress(data2);
|
|
1256
|
+
} catch {
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
const { data } = await client.actions.execute({
|
|
1261
|
+
quote: rawQuote,
|
|
1262
|
+
wallet,
|
|
1263
|
+
onProgress,
|
|
1264
|
+
...options.disableCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: options.disableCapabilitiesCheck } : {}
|
|
1265
|
+
});
|
|
1266
|
+
const requestId = quoteRequestId(data) ?? observedRequestId;
|
|
1267
|
+
const transactions = collectRelayTransactions(data.steps, sourceChainId);
|
|
1268
|
+
return {
|
|
1269
|
+
...requestId ? { requestId } : {},
|
|
1270
|
+
txHashes: relayTransactionHashes(transactions),
|
|
1271
|
+
transactions,
|
|
1272
|
+
quote: redactRelayQuoteRaw(data)
|
|
1273
|
+
};
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
if (isCashError(err)) throw err;
|
|
1276
|
+
const txHashes = relayTransactionHashes(observedTransactions);
|
|
1277
|
+
throw errors.sourceExecutionFailed(err, {
|
|
1278
|
+
...observedRequestId ? { requestId: observedRequestId } : {},
|
|
1279
|
+
txHashes,
|
|
1280
|
+
...txHashes.length > 0 ? { transactions: observedTransactions } : {}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
874
1283
|
}
|
|
875
1284
|
async function readRelayStatus(requestId, options = {}) {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1285
|
+
try {
|
|
1286
|
+
const client = relayClient(options);
|
|
1287
|
+
const response = await client.utils.request({
|
|
1288
|
+
url: `${client.baseApiUrl}/intents/status/v3`,
|
|
1289
|
+
method: "get",
|
|
1290
|
+
params: { requestId }
|
|
1291
|
+
});
|
|
1292
|
+
const root = asRecord(response.data);
|
|
1293
|
+
const status = asString(root.status);
|
|
1294
|
+
if (status !== "refund" && status !== "waiting" && status !== "depositing" && status !== "failure" && status !== "pending" && status !== "submitted" && status !== "success") {
|
|
1295
|
+
throw new Error(`Relay returned unknown status: ${String(root.status)}`);
|
|
1296
|
+
}
|
|
1297
|
+
const details = asString(root.details);
|
|
1298
|
+
const updatedAt = asNumber(root.updatedAt);
|
|
1299
|
+
const originChainId = asNumber(root.originChainId);
|
|
1300
|
+
const destinationChainId = asNumber(root.destinationChainId);
|
|
1301
|
+
const quoteCreatedAt = asNumber(root.quoteCreatedAt);
|
|
1302
|
+
return {
|
|
1303
|
+
requestId,
|
|
1304
|
+
status,
|
|
1305
|
+
...details ? { details } : {},
|
|
1306
|
+
inTxHashes: Array.isArray(root.inTxHashes) ? root.inTxHashes.map(String) : [],
|
|
1307
|
+
txHashes: Array.isArray(root.txHashes) ? root.txHashes.map(String) : [],
|
|
1308
|
+
...updatedAt !== void 0 ? { updatedAt } : {},
|
|
1309
|
+
...originChainId !== void 0 ? { originChainId } : {},
|
|
1310
|
+
...destinationChainId !== void 0 ? { destinationChainId } : {},
|
|
1311
|
+
...quoteCreatedAt !== void 0 ? { quoteCreatedAt } : {},
|
|
1312
|
+
raw: response.data
|
|
1313
|
+
};
|
|
1314
|
+
} catch (err) {
|
|
1315
|
+
if (isCashError(err)) throw err;
|
|
1316
|
+
throw errors.sourceStatusFailed(requestId, err);
|
|
1317
|
+
}
|
|
904
1318
|
}
|
|
905
1319
|
|
|
906
1320
|
// src/client/estimate.ts
|
|
@@ -947,11 +1361,16 @@ async function readEstimate(publicClient, input, context = {}) {
|
|
|
947
1361
|
if (!feedConfig || feedConfig.feed.toLowerCase() === ZERO_ADDRESS) {
|
|
948
1362
|
rate = 1;
|
|
949
1363
|
} else {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1364
|
+
let result;
|
|
1365
|
+
try {
|
|
1366
|
+
result = await publicClient.readContract({
|
|
1367
|
+
address: feedConfig.feed,
|
|
1368
|
+
abi: CHAINLINK_LATEST_ROUND_ABI,
|
|
1369
|
+
functionName: "latestRoundData"
|
|
1370
|
+
});
|
|
1371
|
+
} catch (err) {
|
|
1372
|
+
throw errors.oracleReadFailed(currency, err);
|
|
1373
|
+
}
|
|
955
1374
|
const answer = Number(result[1]);
|
|
956
1375
|
const price = answer / 10 ** feedConfig.decimals;
|
|
957
1376
|
if (!Number.isFinite(price) || price <= 0) {
|
|
@@ -997,6 +1416,7 @@ async function readEstimate(publicClient, input, context = {}) {
|
|
|
997
1416
|
var DEFAULT_RPC_URL = "https://mainnet.base.org";
|
|
998
1417
|
var CASH_ATTRIBUTION_CODE = "peer-cash";
|
|
999
1418
|
var DEFAULT_CURATOR_URLS = {
|
|
1419
|
+
preproduction: "https://api-preprod.zkp2p.xyz",
|
|
1000
1420
|
staging: "https://api-staging.zkp2p.xyz"
|
|
1001
1421
|
};
|
|
1002
1422
|
var ERC20_APPROVE_ABI = viem.parseAbi([
|
|
@@ -1031,12 +1451,29 @@ async function submitAndConfirm(client, verb, send) {
|
|
|
1031
1451
|
try {
|
|
1032
1452
|
hash = await send();
|
|
1033
1453
|
} catch (err) {
|
|
1034
|
-
|
|
1454
|
+
const mapped = mapChainError(verb, err);
|
|
1455
|
+
if (isKnownPreBroadcastFailure(err, mapped)) throw mapped;
|
|
1456
|
+
throw errors.transactionSubmissionUnknown(verb, err, {
|
|
1457
|
+
kind: "inspect-base-operation-submission",
|
|
1458
|
+
operation: verb
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
let receipt;
|
|
1462
|
+
try {
|
|
1463
|
+
receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
1464
|
+
} catch (err) {
|
|
1465
|
+
throw errors.transactionStatusUnknown(hash, err, verb);
|
|
1035
1466
|
}
|
|
1036
|
-
const receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
1037
1467
|
if (receipt.status === "reverted") throw errors.transactionFailed(hash);
|
|
1038
1468
|
return hash;
|
|
1039
1469
|
}
|
|
1470
|
+
function isKnownPreBroadcastFailure(err, mapped) {
|
|
1471
|
+
if (mapped.code === "INSUFFICIENT_TOKEN_BALANCE" || mapped.code === "ALLOWANCE_NOT_VISIBLE" || mapped.code === "ESCROW_PAUSED") {
|
|
1472
|
+
return true;
|
|
1473
|
+
}
|
|
1474
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1475
|
+
return /user rejected|user denied|rejected request|action_rejected/i.test(message);
|
|
1476
|
+
}
|
|
1040
1477
|
function depositOrderOptions(deposit) {
|
|
1041
1478
|
const remaining = toBigIntOrUndefined(deposit.remainingDeposits);
|
|
1042
1479
|
const outstanding = toBigIntOrUndefined(deposit.outstandingIntentAmount);
|
|
@@ -1076,9 +1513,10 @@ function createCashClient(options) {
|
|
|
1076
1513
|
}
|
|
1077
1514
|
const readClient = buildSdkClient(viem.createWalletClient({ chain: chains.base, transport }));
|
|
1078
1515
|
const signingClients = /* @__PURE__ */ new WeakMap();
|
|
1079
|
-
function signingClient(verb, opts) {
|
|
1516
|
+
async function signingClient(verb, opts) {
|
|
1080
1517
|
const signer = opts?.signer;
|
|
1081
1518
|
if (!signer?.account) throw errors.signerRequired(verb);
|
|
1519
|
+
await assertWalletChainId(signer, BASE_CHAIN_ID, verb);
|
|
1082
1520
|
let client = signingClients.get(signer);
|
|
1083
1521
|
if (!client) {
|
|
1084
1522
|
client = buildSdkClient(signer);
|
|
@@ -1088,13 +1526,15 @@ function createCashClient(options) {
|
|
|
1088
1526
|
}
|
|
1089
1527
|
function validatePayout(input) {
|
|
1090
1528
|
const { receive } = input;
|
|
1091
|
-
const
|
|
1092
|
-
|
|
1529
|
+
const platform = buildCapabilities(environment).platforms.find(
|
|
1530
|
+
(capability) => capability.platform === receive.platform
|
|
1531
|
+
);
|
|
1532
|
+
if (!platform) throw errors.unsupportedPlatform(receive.platform);
|
|
1093
1533
|
if (!isMarketRateSupported(receive.currency)) {
|
|
1094
1534
|
throw errors.oracleUnsupportedCurrency(receive.currency);
|
|
1095
1535
|
}
|
|
1096
|
-
if (
|
|
1097
|
-
throw errors.
|
|
1536
|
+
if (!platform.currencies.includes(receive.currency)) {
|
|
1537
|
+
throw errors.unsupportedPlatformCurrency(receive.platform, receive.currency);
|
|
1098
1538
|
}
|
|
1099
1539
|
return {
|
|
1100
1540
|
payouts: [
|
|
@@ -1103,15 +1543,22 @@ function createCashClient(options) {
|
|
|
1103
1543
|
currency: receive.currency,
|
|
1104
1544
|
payeeData: receive.payee
|
|
1105
1545
|
}
|
|
1106
|
-
]
|
|
1107
|
-
...input.intentAmountRange ? { intentAmountRange: input.intentAmountRange } : {}
|
|
1546
|
+
]
|
|
1108
1547
|
};
|
|
1109
1548
|
}
|
|
1110
|
-
function
|
|
1111
|
-
if (
|
|
1112
|
-
throw errors.amountBelowMinimum(
|
|
1549
|
+
function validateDepositInput(amount, input, payoutInput = validatePayout(input)) {
|
|
1550
|
+
if (amount < MIN_CASHOUT_AMOUNT) {
|
|
1551
|
+
throw errors.amountBelowMinimum(amount, MIN_CASHOUT_AMOUNT);
|
|
1113
1552
|
}
|
|
1114
|
-
|
|
1553
|
+
const range = input.intentAmountRange;
|
|
1554
|
+
if (range && (range.min <= 0n || range.max < range.min || range.max > amount)) {
|
|
1555
|
+
throw errors.invalidIntentAmountRange(amount, range.min, range.max);
|
|
1556
|
+
}
|
|
1557
|
+
return {
|
|
1558
|
+
amount,
|
|
1559
|
+
...payoutInput,
|
|
1560
|
+
...range ? { intentAmountRange: range } : {}
|
|
1561
|
+
};
|
|
1115
1562
|
}
|
|
1116
1563
|
async function buildDepositParams(client, depositInput) {
|
|
1117
1564
|
try {
|
|
@@ -1126,32 +1573,54 @@ function createCashClient(options) {
|
|
|
1126
1573
|
throw errors.payeeRegistrationFailed(err);
|
|
1127
1574
|
}
|
|
1128
1575
|
}
|
|
1576
|
+
function parseDepositId(depositId) {
|
|
1577
|
+
try {
|
|
1578
|
+
const parsed = parseCompositeDepositId(depositId);
|
|
1579
|
+
return {
|
|
1580
|
+
...parsed,
|
|
1581
|
+
compositeId: sdk.createCompositeDepositId(parsed.escrowAddress, parsed.onchainDepositId)
|
|
1582
|
+
};
|
|
1583
|
+
} catch (err) {
|
|
1584
|
+
throw errors.invalidDepositId(depositId, err);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1129
1587
|
async function fetchOrder(depositId) {
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1588
|
+
const { compositeId } = parseDepositId(depositId);
|
|
1589
|
+
let deposits;
|
|
1590
|
+
try {
|
|
1591
|
+
deposits = await readClient.indexer.getDepositsByIdsWithRelations([compositeId], {
|
|
1592
|
+
includeIntents: true,
|
|
1593
|
+
intentStatuses: CASH_ORDER_STATUSES
|
|
1594
|
+
});
|
|
1595
|
+
} catch (err) {
|
|
1596
|
+
throw errors.indexerUnavailable("order", err);
|
|
1597
|
+
}
|
|
1134
1598
|
const deposit = deposits[0];
|
|
1135
1599
|
if (!deposit) {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1600
|
+
let intents;
|
|
1601
|
+
try {
|
|
1602
|
+
intents = await readClient.indexer.getIntentsForDeposits(
|
|
1603
|
+
[compositeId],
|
|
1604
|
+
CASH_ORDER_STATUSES
|
|
1605
|
+
);
|
|
1606
|
+
} catch (err) {
|
|
1607
|
+
throw errors.indexerUnavailable("order intents", err);
|
|
1608
|
+
}
|
|
1609
|
+
if (intents.length === 0) throw errors.orderNotFound(compositeId);
|
|
1610
|
+
return deriveCashOrder(compositeId, intents);
|
|
1142
1611
|
}
|
|
1143
1612
|
const payouts = derivePayouts(
|
|
1144
1613
|
deposit.paymentMethods ?? [],
|
|
1145
1614
|
deposit.currencies ?? [],
|
|
1146
1615
|
sdk.getPaymentMethodsCatalog(BASE_CHAIN_ID, environment)
|
|
1147
1616
|
);
|
|
1148
|
-
return deriveCashOrder(
|
|
1617
|
+
return deriveCashOrder(compositeId, deposit.intents ?? [], {
|
|
1149
1618
|
...depositOrderOptions(deposit),
|
|
1150
1619
|
...payouts.length > 0 ? { payouts } : {}
|
|
1151
1620
|
});
|
|
1152
1621
|
}
|
|
1153
1622
|
function escrowContext(depositId) {
|
|
1154
|
-
const { escrowAddress, onchainDepositId } =
|
|
1623
|
+
const { escrowAddress, onchainDepositId } = parseDepositId(depositId);
|
|
1155
1624
|
return {
|
|
1156
1625
|
onchainDepositId,
|
|
1157
1626
|
escrowArg: escrowAddress ? { escrowAddress } : {}
|
|
@@ -1166,7 +1635,7 @@ function createCashClient(options) {
|
|
|
1166
1635
|
const signaled = order.fills.filter((f) => f.status === "SIGNALED");
|
|
1167
1636
|
const liveIntent = signaled.some((f) => isFillLive(f, nowSeconds));
|
|
1168
1637
|
const expiredIntent = signaled.length > 0 && !liveIntent;
|
|
1169
|
-
if (order.pendingAmount > 0n &&
|
|
1638
|
+
if (liveIntent || order.pendingAmount > 0n && signaled.length === 0) {
|
|
1170
1639
|
throw errors.activeIntentBlocksWithdrawal(depositId);
|
|
1171
1640
|
}
|
|
1172
1641
|
if (availableAmount(order) <= 0n && order.pendingAmount === 0n) {
|
|
@@ -1207,22 +1676,32 @@ function createCashClient(options) {
|
|
|
1207
1676
|
txOverrides: attribution
|
|
1208
1677
|
});
|
|
1209
1678
|
} catch (err) {
|
|
1210
|
-
throw mapChainError("approve", err);
|
|
1679
|
+
throw mapChainError("approve", err, { requiredAmount: amount });
|
|
1211
1680
|
}
|
|
1212
1681
|
if (allowance.hadAllowance || !allowance.hash) return;
|
|
1213
|
-
|
|
1682
|
+
let receipt;
|
|
1683
|
+
try {
|
|
1684
|
+
receipt = await client.publicClient.waitForTransactionReceipt({ hash: allowance.hash });
|
|
1685
|
+
} catch (err) {
|
|
1686
|
+
throw errors.transactionStatusUnknown(allowance.hash, err, "approve");
|
|
1687
|
+
}
|
|
1214
1688
|
if (receipt.status === "reverted") throw errors.transactionFailed(allowance.hash);
|
|
1689
|
+
let lastReadError;
|
|
1215
1690
|
for (let attempt = 0; attempt < 15; attempt++) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1691
|
+
try {
|
|
1692
|
+
const visible = await client.publicClient.readContract({
|
|
1693
|
+
address: token,
|
|
1694
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
1695
|
+
functionName: "allowance",
|
|
1696
|
+
args: [owner, escrow]
|
|
1697
|
+
});
|
|
1698
|
+
if (visible >= amount) return;
|
|
1699
|
+
} catch (err) {
|
|
1700
|
+
lastReadError = err;
|
|
1701
|
+
}
|
|
1223
1702
|
await sleep(1e3);
|
|
1224
1703
|
}
|
|
1225
|
-
throw errors.allowanceNotVisible(amount);
|
|
1704
|
+
throw errors.allowanceNotVisible(amount, lastReadError);
|
|
1226
1705
|
}
|
|
1227
1706
|
return {
|
|
1228
1707
|
capabilities,
|
|
@@ -1233,8 +1712,10 @@ function createCashClient(options) {
|
|
|
1233
1712
|
return quoteRelayToBaseUsdc(input, options.relay);
|
|
1234
1713
|
},
|
|
1235
1714
|
async executeSourceQuote(quote, opts) {
|
|
1715
|
+
if (!opts.signer.account) throw errors.signerRequired("executeSourceQuote");
|
|
1236
1716
|
return executeRelayQuote(quote, opts.signer, {
|
|
1237
1717
|
...options.relay ? { relay: options.relay } : {},
|
|
1718
|
+
...opts.recipient ? { recipient: opts.recipient } : {},
|
|
1238
1719
|
...opts.onProgress ? { onProgress: opts.onProgress } : {},
|
|
1239
1720
|
...opts.disableCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: opts.disableCapabilitiesCheck } : {}
|
|
1240
1721
|
});
|
|
@@ -1250,7 +1731,7 @@ function createCashClient(options) {
|
|
|
1250
1731
|
});
|
|
1251
1732
|
},
|
|
1252
1733
|
async cashout(input, opts) {
|
|
1253
|
-
const client = signingClient("cashout", opts);
|
|
1734
|
+
const client = await signingClient("cashout", opts);
|
|
1254
1735
|
const owner = opts.signer.account.address;
|
|
1255
1736
|
const payoutInput = validatePayout(input);
|
|
1256
1737
|
let sourceResult;
|
|
@@ -1258,6 +1739,7 @@ function createCashClient(options) {
|
|
|
1258
1739
|
if (input.source) {
|
|
1259
1740
|
const sourceSigner = opts.sourceSigner ?? (input.source.chainId === BASE_CHAIN_ID ? opts.signer : void 0);
|
|
1260
1741
|
if (!sourceSigner?.account) throw errors.signerRequired("source cashout");
|
|
1742
|
+
await assertWalletChainId(sourceSigner, input.source.chainId, "source cashout");
|
|
1261
1743
|
if (input.source.recipient !== void 0 && input.source.recipient.toLowerCase() !== owner.toLowerCase()) {
|
|
1262
1744
|
throw errors.sourceRecipientMismatch(input.source.recipient, owner);
|
|
1263
1745
|
}
|
|
@@ -1275,20 +1757,23 @@ function createCashClient(options) {
|
|
|
1275
1757
|
throw errors.amountBelowMinimum(relayQuote.outputAmount, MIN_CASHOUT_AMOUNT);
|
|
1276
1758
|
}
|
|
1277
1759
|
cashoutAmount = relayQuote.outputAmount;
|
|
1278
|
-
const depositInput2 =
|
|
1760
|
+
const depositInput2 = validateDepositInput(cashoutAmount, input, payoutInput);
|
|
1279
1761
|
const params2 = await buildDepositParams(client, depositInput2);
|
|
1280
1762
|
const escrow2 = client.escrowV2Address ?? client.escrowAddress;
|
|
1281
1763
|
await settleAllowance(client, params2.token, owner, escrow2, depositInput2.amount);
|
|
1282
1764
|
const executed = await executeRelayQuote(relayQuote.raw, sourceSigner, {
|
|
1283
1765
|
...options.relay ? { relay: options.relay } : {},
|
|
1766
|
+
recipient: owner,
|
|
1284
1767
|
...opts.onSourceProgress ? { onProgress: opts.onSourceProgress } : {},
|
|
1285
1768
|
...opts.disableSourceCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: opts.disableSourceCapabilitiesCheck } : {}
|
|
1286
1769
|
});
|
|
1287
|
-
|
|
1770
|
+
const routedSource = {
|
|
1288
1771
|
amount: cashoutAmount,
|
|
1289
1772
|
...executed.requestId ? { requestId: executed.requestId } : {},
|
|
1290
|
-
txHashes: executed.txHashes
|
|
1773
|
+
txHashes: executed.txHashes,
|
|
1774
|
+
...executed.transactions ? { transactions: executed.transactions } : {}
|
|
1291
1775
|
};
|
|
1776
|
+
sourceResult = routedSource;
|
|
1292
1777
|
const attributedParams2 = { ...params2, txOverrides: attribution };
|
|
1293
1778
|
const send2 = async () => {
|
|
1294
1779
|
try {
|
|
@@ -1305,10 +1790,26 @@ function createCashClient(options) {
|
|
|
1305
1790
|
try {
|
|
1306
1791
|
hash2 = await send2();
|
|
1307
1792
|
} catch (err) {
|
|
1308
|
-
|
|
1793
|
+
const mapped = mapChainError("createDeposit", err, {
|
|
1794
|
+
requiredAmount: depositInput2.amount
|
|
1795
|
+
});
|
|
1796
|
+
if (isKnownPreBroadcastFailure(err, mapped)) {
|
|
1797
|
+
throw errors.sourceRouteCompletedCashoutFailed(routedSource, mapped);
|
|
1798
|
+
}
|
|
1799
|
+
throw errors.sourceCashoutSubmissionUnknown(routedSource, owner, mapped);
|
|
1800
|
+
}
|
|
1801
|
+
let receipt2;
|
|
1802
|
+
try {
|
|
1803
|
+
receipt2 = await client.publicClient.waitForTransactionReceipt({ hash: hash2 });
|
|
1804
|
+
} catch (err) {
|
|
1805
|
+
throw errors.sourceCashoutStatusUnknown(routedSource, hash2, err);
|
|
1806
|
+
}
|
|
1807
|
+
if (receipt2.status === "reverted") {
|
|
1808
|
+
throw errors.sourceRouteCompletedCashoutFailed(
|
|
1809
|
+
routedSource,
|
|
1810
|
+
errors.transactionFailed(hash2)
|
|
1811
|
+
);
|
|
1309
1812
|
}
|
|
1310
|
-
const receipt2 = await client.publicClient.waitForTransactionReceipt({ hash: hash2 });
|
|
1311
|
-
if (receipt2.status === "reverted") throw errors.transactionFailed(hash2);
|
|
1312
1813
|
const abi2 = client.escrowV2Abi ?? client.escrowAbi;
|
|
1313
1814
|
const resolved2 = resolveCashDepositId({ logs: receipt2.logs, abi: abi2 });
|
|
1314
1815
|
if (!resolved2) throw errors.depositResolutionFailed(hash2);
|
|
@@ -1322,10 +1823,10 @@ function createCashClient(options) {
|
|
|
1322
1823
|
escrowAddress: resolved2.escrowAddress,
|
|
1323
1824
|
onchainDepositId: resolved2.onchainDepositId,
|
|
1324
1825
|
order: order2,
|
|
1325
|
-
source:
|
|
1826
|
+
source: routedSource
|
|
1326
1827
|
};
|
|
1327
1828
|
}
|
|
1328
|
-
const depositInput =
|
|
1829
|
+
const depositInput = validateDepositInput(input.amount, input, payoutInput);
|
|
1329
1830
|
const params = await buildDepositParams(client, depositInput);
|
|
1330
1831
|
const escrow = client.escrowV2Address ?? client.escrowAddress;
|
|
1331
1832
|
await settleAllowance(client, params.token, owner, escrow, depositInput.amount);
|
|
@@ -1345,9 +1846,23 @@ function createCashClient(options) {
|
|
|
1345
1846
|
try {
|
|
1346
1847
|
hash = await send();
|
|
1347
1848
|
} catch (err) {
|
|
1348
|
-
|
|
1849
|
+
const mapped = mapChainError("createDeposit", err, {
|
|
1850
|
+
requiredAmount: depositInput.amount
|
|
1851
|
+
});
|
|
1852
|
+
if (isKnownPreBroadcastFailure(err, mapped)) throw mapped;
|
|
1853
|
+
throw errors.transactionSubmissionUnknown("cashout", err, {
|
|
1854
|
+
kind: "inspect-base-cashout-submission",
|
|
1855
|
+
amount: depositInput.amount.toString(),
|
|
1856
|
+
depositor: owner,
|
|
1857
|
+
txHashes: []
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
let receipt;
|
|
1861
|
+
try {
|
|
1862
|
+
receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
1863
|
+
} catch (err) {
|
|
1864
|
+
throw errors.transactionStatusUnknown(hash, err, "cashout");
|
|
1349
1865
|
}
|
|
1350
|
-
const receipt = await client.publicClient.waitForTransactionReceipt({ hash });
|
|
1351
1866
|
if (receipt.status === "reverted") throw errors.transactionFailed(hash);
|
|
1352
1867
|
const abi = client.escrowV2Abi ?? client.escrowAbi;
|
|
1353
1868
|
const resolved = resolveCashDepositId({ logs: receipt.logs, abi });
|
|
@@ -1367,7 +1882,7 @@ function createCashClient(options) {
|
|
|
1367
1882
|
},
|
|
1368
1883
|
async prepare(input) {
|
|
1369
1884
|
if (input.source) throw errors.sourceRouteUnsupportedInPrepare();
|
|
1370
|
-
const depositInput =
|
|
1885
|
+
const depositInput = validateDepositInput(input.amount, input);
|
|
1371
1886
|
const params = await buildDepositParams(readClient, depositInput);
|
|
1372
1887
|
const { prepared } = await readClient.prepareCreateDeposit({
|
|
1373
1888
|
...params,
|
|
@@ -1406,13 +1921,46 @@ function createCashClient(options) {
|
|
|
1406
1921
|
return fetchOrder(depositId);
|
|
1407
1922
|
},
|
|
1408
1923
|
async buyer(address) {
|
|
1409
|
-
|
|
1924
|
+
let intents;
|
|
1925
|
+
try {
|
|
1926
|
+
intents = await readClient.indexer.getOwnerIntents(address, CASH_ORDER_STATUSES);
|
|
1927
|
+
} catch (err) {
|
|
1928
|
+
throw errors.indexerUnavailable("buyer profile", err);
|
|
1929
|
+
}
|
|
1410
1930
|
return deriveBuyerProfile(address, intents);
|
|
1411
1931
|
},
|
|
1412
1932
|
async orders(owner, opts = {}) {
|
|
1413
1933
|
const { inFlight = false, limit = 100 } = opts;
|
|
1414
|
-
|
|
1415
|
-
|
|
1934
|
+
let deposits;
|
|
1935
|
+
try {
|
|
1936
|
+
deposits = await readClient.indexer.getDepositsWithRelations(
|
|
1937
|
+
{ depositor: owner },
|
|
1938
|
+
{ limit }
|
|
1939
|
+
);
|
|
1940
|
+
} catch (err) {
|
|
1941
|
+
throw errors.indexerUnavailable("orders", err);
|
|
1942
|
+
}
|
|
1943
|
+
const catalog = sdk.getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
|
|
1944
|
+
const derived = deposits.flatMap((deposit) => {
|
|
1945
|
+
if (deposit.token.toLowerCase() !== BASE_USDC_ADDRESS.toLowerCase()) return [];
|
|
1946
|
+
const payouts = derivePayouts(
|
|
1947
|
+
deposit.paymentMethods ?? [],
|
|
1948
|
+
deposit.currencies ?? [],
|
|
1949
|
+
catalog
|
|
1950
|
+
);
|
|
1951
|
+
if (payouts.length !== 1 || !payouts.every((payout) => payout.pricing.marketRate && payout.pricing.spreadBps === 0)) {
|
|
1952
|
+
return [];
|
|
1953
|
+
}
|
|
1954
|
+
return [
|
|
1955
|
+
deriveCashOrder(deposit.id, [], {
|
|
1956
|
+
...depositOrderOptions(deposit),
|
|
1957
|
+
payouts,
|
|
1958
|
+
// List rows carry no intent detail - a positive outstanding
|
|
1959
|
+
// amount is treated conservatively as a live lock.
|
|
1960
|
+
fillsIncluded: false
|
|
1961
|
+
})
|
|
1962
|
+
];
|
|
1963
|
+
}).filter((o) => o.totalAmount >= MIN_CASHOUT_AMOUNT).sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
|
1416
1964
|
return inFlight ? derived.filter((o) => o.isInFlight) : derived;
|
|
1417
1965
|
},
|
|
1418
1966
|
async *watch(depositId, opts = {}) {
|
|
@@ -1442,7 +1990,7 @@ function createCashClient(options) {
|
|
|
1442
1990
|
}
|
|
1443
1991
|
},
|
|
1444
1992
|
async withdraw(depositId, opts) {
|
|
1445
|
-
const client = signingClient("withdraw", opts);
|
|
1993
|
+
const client = await signingClient("withdraw", opts);
|
|
1446
1994
|
if (opts.amount !== void 0) {
|
|
1447
1995
|
const { onchainDepositId: onchainDepositId2, escrowArg: escrowArg2 } = await partialWithdrawContext(
|
|
1448
1996
|
depositId,
|
|
@@ -1540,7 +2088,7 @@ function createCashClient(options) {
|
|
|
1540
2088
|
return { txs, steps };
|
|
1541
2089
|
},
|
|
1542
2090
|
async topUp(depositId, amount, opts) {
|
|
1543
|
-
const client = signingClient("topUp", opts);
|
|
2091
|
+
const client = await signingClient("topUp", opts);
|
|
1544
2092
|
const { onchainDepositId, escrowArg } = await topUpContext(depositId, amount);
|
|
1545
2093
|
const owner = opts.signer.account.address;
|
|
1546
2094
|
const escrow = escrowArg.escrowAddress ?? client.escrowV2Address ?? client.escrowAddress;
|
|
@@ -1595,6 +2143,39 @@ function createCashClient(options) {
|
|
|
1595
2143
|
};
|
|
1596
2144
|
}
|
|
1597
2145
|
var bigintString = zod.z.string().regex(/^-?\d+$/, "expected a decimal bigint string");
|
|
2146
|
+
var nonNegativeBigintString = zod.z.string().regex(/^\d+$/, "expected a non-negative decimal bigint string");
|
|
2147
|
+
var relayTransactionJsonSchema = zod.z.object({
|
|
2148
|
+
hash: zod.z.string(),
|
|
2149
|
+
chainId: zod.z.number()
|
|
2150
|
+
});
|
|
2151
|
+
var relayTransactionsJsonSchema = zod.z.object({
|
|
2152
|
+
origin: zod.z.array(relayTransactionJsonSchema),
|
|
2153
|
+
destination: zod.z.array(relayTransactionJsonSchema)
|
|
2154
|
+
}).strict();
|
|
2155
|
+
var cashAssetJsonSchema = zod.z.object({
|
|
2156
|
+
chainId: zod.z.number(),
|
|
2157
|
+
address: zod.z.string(),
|
|
2158
|
+
symbol: zod.z.string(),
|
|
2159
|
+
decimals: zod.z.number(),
|
|
2160
|
+
name: zod.z.string().optional(),
|
|
2161
|
+
isNative: zod.z.boolean().optional()
|
|
2162
|
+
});
|
|
2163
|
+
var cashChainJsonSchema = zod.z.object({
|
|
2164
|
+
id: zod.z.number(),
|
|
2165
|
+
name: zod.z.string(),
|
|
2166
|
+
displayName: zod.z.string(),
|
|
2167
|
+
disabled: zod.z.boolean(),
|
|
2168
|
+
depositEnabled: zod.z.boolean(),
|
|
2169
|
+
blockProductionLagging: zod.z.boolean(),
|
|
2170
|
+
vmType: zod.z.string().optional(),
|
|
2171
|
+
tokens: zod.z.array(cashAssetJsonSchema)
|
|
2172
|
+
});
|
|
2173
|
+
var cashSourceCapabilitiesJsonSchema = zod.z.object({
|
|
2174
|
+
destination: cashAssetJsonSchema,
|
|
2175
|
+
chains: zod.z.array(cashChainJsonSchema),
|
|
2176
|
+
source: zod.z.literal("relay-sdk"),
|
|
2177
|
+
asOf: zod.z.number()
|
|
2178
|
+
});
|
|
1598
2179
|
var cashOrderStateSchema = zod.z.enum([
|
|
1599
2180
|
"awaiting-buyer",
|
|
1600
2181
|
"matched",
|
|
@@ -1607,18 +2188,18 @@ var intentStatusSchema = zod.z.enum(["SIGNALED", "FULFILLED", "PRUNED", "MANUALL
|
|
|
1607
2188
|
var cashFillJsonSchema = zod.z.object({
|
|
1608
2189
|
intentHash: zod.z.string(),
|
|
1609
2190
|
status: intentStatusSchema,
|
|
1610
|
-
amount:
|
|
2191
|
+
amount: nonNegativeBigintString,
|
|
1611
2192
|
buyer: zod.z.string(),
|
|
1612
2193
|
currency: zod.z.string().optional(),
|
|
1613
2194
|
currencyHash: zod.z.string().optional(),
|
|
1614
2195
|
rate: zod.z.number().optional(),
|
|
1615
|
-
conversionRate:
|
|
2196
|
+
conversionRate: nonNegativeBigintString.optional(),
|
|
1616
2197
|
fiatOwed: zod.z.number().optional(),
|
|
1617
2198
|
fiatPaid: zod.z.number().optional(),
|
|
1618
2199
|
paidCurrency: zod.z.string().optional(),
|
|
1619
2200
|
paymentId: zod.z.string().optional(),
|
|
1620
2201
|
paidAt: zod.z.number().optional(),
|
|
1621
|
-
releasedAmount:
|
|
2202
|
+
releasedAmount: nonNegativeBigintString.optional(),
|
|
1622
2203
|
fillLatencySeconds: zod.z.number().optional(),
|
|
1623
2204
|
isExpired: zod.z.boolean().optional(),
|
|
1624
2205
|
signaledAt: zod.z.number().optional(),
|
|
@@ -1657,10 +2238,10 @@ var cashOrderJsonSchema = zod.z.object({
|
|
|
1657
2238
|
depositId: zod.z.string(),
|
|
1658
2239
|
state: cashOrderStateSchema,
|
|
1659
2240
|
fills: zod.z.array(cashFillJsonSchema),
|
|
1660
|
-
totalAmount:
|
|
1661
|
-
filledAmount:
|
|
1662
|
-
pendingAmount:
|
|
1663
|
-
returnedAmount:
|
|
2241
|
+
totalAmount: nonNegativeBigintString,
|
|
2242
|
+
filledAmount: nonNegativeBigintString,
|
|
2243
|
+
pendingAmount: nonNegativeBigintString,
|
|
2244
|
+
returnedAmount: nonNegativeBigintString,
|
|
1664
2245
|
nextActions: zod.z.array(cashNextActionSchema),
|
|
1665
2246
|
primaryIntentHash: zod.z.string().optional(),
|
|
1666
2247
|
matchedAt: zod.z.number().optional(),
|
|
@@ -1675,7 +2256,7 @@ var cashOrderJsonSchema = zod.z.object({
|
|
|
1675
2256
|
var cashEstimateJsonSchema = zod.z.object({
|
|
1676
2257
|
kind: zod.z.literal("oracle-estimate"),
|
|
1677
2258
|
currency: zod.z.string(),
|
|
1678
|
-
amount:
|
|
2259
|
+
amount: nonNegativeBigintString,
|
|
1679
2260
|
rate: zod.z.number(),
|
|
1680
2261
|
receiveAmount: zod.z.number(),
|
|
1681
2262
|
asOf: zod.z.number(),
|
|
@@ -1691,7 +2272,7 @@ var cashEstimateJsonSchema = zod.z.object({
|
|
|
1691
2272
|
name: zod.z.string().optional(),
|
|
1692
2273
|
isNative: zod.z.boolean().optional()
|
|
1693
2274
|
}),
|
|
1694
|
-
inputAmount:
|
|
2275
|
+
inputAmount: nonNegativeBigintString,
|
|
1695
2276
|
relayQuote: zod.z.object({
|
|
1696
2277
|
requestId: zod.z.string().optional(),
|
|
1697
2278
|
source: zod.z.object({
|
|
@@ -1710,8 +2291,8 @@ var cashEstimateJsonSchema = zod.z.object({
|
|
|
1710
2291
|
name: zod.z.string().optional(),
|
|
1711
2292
|
isNative: zod.z.boolean().optional()
|
|
1712
2293
|
}),
|
|
1713
|
-
inputAmount:
|
|
1714
|
-
outputAmount:
|
|
2294
|
+
inputAmount: nonNegativeBigintString,
|
|
2295
|
+
outputAmount: nonNegativeBigintString,
|
|
1715
2296
|
rate: zod.z.number().optional(),
|
|
1716
2297
|
timeEstimateSeconds: zod.z.number().optional(),
|
|
1717
2298
|
fees: zod.z.unknown().optional(),
|
|
@@ -1719,7 +2300,7 @@ var cashEstimateJsonSchema = zod.z.object({
|
|
|
1719
2300
|
zod.z.object({
|
|
1720
2301
|
to: zod.z.string(),
|
|
1721
2302
|
data: zod.z.string(),
|
|
1722
|
-
value:
|
|
2303
|
+
value: nonNegativeBigintString,
|
|
1723
2304
|
chainId: zod.z.number()
|
|
1724
2305
|
})
|
|
1725
2306
|
),
|
|
@@ -1734,9 +2315,39 @@ var cashEstimateJsonSchema = zod.z.object({
|
|
|
1734
2315
|
var preparedTransactionJsonSchema = zod.z.object({
|
|
1735
2316
|
to: zod.z.string(),
|
|
1736
2317
|
data: zod.z.string(),
|
|
1737
|
-
value:
|
|
2318
|
+
value: nonNegativeBigintString,
|
|
1738
2319
|
chainId: zod.z.number()
|
|
1739
2320
|
});
|
|
2321
|
+
var relayQuoteJsonSchema = zod.z.object({
|
|
2322
|
+
requestId: zod.z.string().optional(),
|
|
2323
|
+
source: cashAssetJsonSchema,
|
|
2324
|
+
destination: cashAssetJsonSchema,
|
|
2325
|
+
inputAmount: nonNegativeBigintString,
|
|
2326
|
+
outputAmount: nonNegativeBigintString,
|
|
2327
|
+
rate: zod.z.number().optional(),
|
|
2328
|
+
timeEstimateSeconds: zod.z.number().optional(),
|
|
2329
|
+
fees: zod.z.unknown().optional(),
|
|
2330
|
+
txs: zod.z.array(preparedTransactionJsonSchema),
|
|
2331
|
+
raw: zod.z.unknown()
|
|
2332
|
+
});
|
|
2333
|
+
var relayStatusJsonSchema = zod.z.object({
|
|
2334
|
+
requestId: zod.z.string(),
|
|
2335
|
+
status: zod.z.enum(["refund", "waiting", "depositing", "failure", "pending", "submitted", "success"]),
|
|
2336
|
+
details: zod.z.string().optional(),
|
|
2337
|
+
inTxHashes: zod.z.array(zod.z.string()),
|
|
2338
|
+
txHashes: zod.z.array(zod.z.string()),
|
|
2339
|
+
updatedAt: zod.z.number().optional(),
|
|
2340
|
+
originChainId: zod.z.number().optional(),
|
|
2341
|
+
destinationChainId: zod.z.number().optional(),
|
|
2342
|
+
quoteCreatedAt: zod.z.number().optional(),
|
|
2343
|
+
raw: zod.z.unknown()
|
|
2344
|
+
});
|
|
2345
|
+
var relayExecutionResultJsonSchema = zod.z.object({
|
|
2346
|
+
requestId: zod.z.string().optional(),
|
|
2347
|
+
txHashes: zod.z.array(zod.z.string()),
|
|
2348
|
+
transactions: relayTransactionsJsonSchema.optional(),
|
|
2349
|
+
quote: zod.z.unknown()
|
|
2350
|
+
});
|
|
1740
2351
|
var cashPreparedStepJsonSchema = zod.z.object({
|
|
1741
2352
|
kind: zod.z.enum([
|
|
1742
2353
|
"approve",
|
|
@@ -1752,12 +2363,13 @@ var cashoutResultJsonSchema = zod.z.object({
|
|
|
1752
2363
|
depositId: zod.z.string(),
|
|
1753
2364
|
txHash: zod.z.string(),
|
|
1754
2365
|
escrowAddress: zod.z.string(),
|
|
1755
|
-
onchainDepositId:
|
|
2366
|
+
onchainDepositId: nonNegativeBigintString,
|
|
1756
2367
|
order: cashOrderJsonSchema,
|
|
1757
2368
|
source: zod.z.object({
|
|
1758
|
-
amount:
|
|
2369
|
+
amount: nonNegativeBigintString,
|
|
1759
2370
|
requestId: zod.z.string().optional(),
|
|
1760
|
-
txHashes: zod.z.array(zod.z.string())
|
|
2371
|
+
txHashes: zod.z.array(zod.z.string()),
|
|
2372
|
+
transactions: relayTransactionsJsonSchema.optional()
|
|
1761
2373
|
}).optional()
|
|
1762
2374
|
});
|
|
1763
2375
|
var prepareResultJsonSchema = zod.z.object({
|
|
@@ -1787,39 +2399,7 @@ var cashCapabilitiesJsonSchema = zod.z.object({
|
|
|
1787
2399
|
chainId: zod.z.number(),
|
|
1788
2400
|
token: zod.z.object({ address: zod.z.string(), symbol: zod.z.literal("USDC"), decimals: zod.z.number() })
|
|
1789
2401
|
}),
|
|
1790
|
-
relay:
|
|
1791
|
-
destination: zod.z.object({
|
|
1792
|
-
chainId: zod.z.number(),
|
|
1793
|
-
address: zod.z.string(),
|
|
1794
|
-
symbol: zod.z.string(),
|
|
1795
|
-
decimals: zod.z.number(),
|
|
1796
|
-
name: zod.z.string().optional(),
|
|
1797
|
-
isNative: zod.z.boolean().optional()
|
|
1798
|
-
}),
|
|
1799
|
-
chains: zod.z.array(
|
|
1800
|
-
zod.z.object({
|
|
1801
|
-
id: zod.z.number(),
|
|
1802
|
-
name: zod.z.string(),
|
|
1803
|
-
displayName: zod.z.string(),
|
|
1804
|
-
disabled: zod.z.boolean(),
|
|
1805
|
-
depositEnabled: zod.z.boolean(),
|
|
1806
|
-
blockProductionLagging: zod.z.boolean(),
|
|
1807
|
-
vmType: zod.z.string().optional(),
|
|
1808
|
-
tokens: zod.z.array(
|
|
1809
|
-
zod.z.object({
|
|
1810
|
-
chainId: zod.z.number(),
|
|
1811
|
-
address: zod.z.string(),
|
|
1812
|
-
symbol: zod.z.string(),
|
|
1813
|
-
decimals: zod.z.number(),
|
|
1814
|
-
name: zod.z.string().optional(),
|
|
1815
|
-
isNative: zod.z.boolean().optional()
|
|
1816
|
-
})
|
|
1817
|
-
)
|
|
1818
|
-
})
|
|
1819
|
-
),
|
|
1820
|
-
source: zod.z.literal("relay-sdk"),
|
|
1821
|
-
asOf: zod.z.number()
|
|
1822
|
-
}).optional()
|
|
2402
|
+
relay: cashSourceCapabilitiesJsonSchema.optional()
|
|
1823
2403
|
}),
|
|
1824
2404
|
platforms: zod.z.array(
|
|
1825
2405
|
zod.z.object({
|
|
@@ -1830,15 +2410,98 @@ var cashCapabilitiesJsonSchema = zod.z.object({
|
|
|
1830
2410
|
})
|
|
1831
2411
|
),
|
|
1832
2412
|
currencies: zod.z.array(zod.z.string()),
|
|
1833
|
-
amount: zod.z.object({
|
|
2413
|
+
amount: zod.z.object({
|
|
2414
|
+
min: nonNegativeBigintString,
|
|
2415
|
+
recommendedMin: nonNegativeBigintString,
|
|
2416
|
+
max: zod.z.null()
|
|
2417
|
+
}),
|
|
1834
2418
|
pricing: zod.z.object({ kind: zod.z.literal("oracle-market-rate"), spreadBps: zod.z.literal(0) })
|
|
1835
2419
|
});
|
|
2420
|
+
function defineCashErrorCodes(codes) {
|
|
2421
|
+
return codes;
|
|
2422
|
+
}
|
|
2423
|
+
var CASH_ERROR_CODES = defineCashErrorCodes([
|
|
2424
|
+
"ORACLE_UNSUPPORTED_CURRENCY",
|
|
2425
|
+
"ORACLE_READ_FAILED",
|
|
2426
|
+
"UNSUPPORTED_PLATFORM",
|
|
2427
|
+
"UNSUPPORTED_PLATFORM_CURRENCY",
|
|
2428
|
+
"AMOUNT_BELOW_MINIMUM",
|
|
2429
|
+
"INVALID_INTENT_AMOUNT_RANGE",
|
|
2430
|
+
"ACTIVE_INTENT_BLOCKS_WITHDRAWAL",
|
|
2431
|
+
"NOTHING_TO_WITHDRAW",
|
|
2432
|
+
"INSUFFICIENT_AVAILABLE_FUNDS",
|
|
2433
|
+
"INSUFFICIENT_TOKEN_BALANCE",
|
|
2434
|
+
"ORDER_NOT_ACTIVE",
|
|
2435
|
+
"INVALID_DEPOSIT_ID",
|
|
2436
|
+
"ESCROW_PAUSED",
|
|
2437
|
+
"INDEXER_LAG",
|
|
2438
|
+
"INDEXER_UNAVAILABLE",
|
|
2439
|
+
"ORDER_NOT_FOUND",
|
|
2440
|
+
"PAYEE_REGISTRATION_FAILED",
|
|
2441
|
+
"PAYEE_VERIFICATION_REQUIRED",
|
|
2442
|
+
"SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
|
|
2443
|
+
"SOURCE_RECIPIENT_MISMATCH",
|
|
2444
|
+
"SOURCE_CAPABILITIES_FAILED",
|
|
2445
|
+
"SOURCE_QUOTE_FAILED",
|
|
2446
|
+
"SOURCE_EXECUTION_FAILED",
|
|
2447
|
+
"SOURCE_STATUS_FAILED",
|
|
2448
|
+
"SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED",
|
|
2449
|
+
"SOURCE_CASHOUT_SUBMISSION_UNKNOWN",
|
|
2450
|
+
"SOURCE_CASHOUT_STATUS_UNKNOWN",
|
|
2451
|
+
"DEPOSIT_RESOLUTION_FAILED",
|
|
2452
|
+
"ALLOWANCE_NOT_VISIBLE",
|
|
2453
|
+
"SIGNER_REQUIRED",
|
|
2454
|
+
"SIGNER_CHAIN_MISMATCH",
|
|
2455
|
+
"SIGNER_CHAIN_UNAVAILABLE",
|
|
2456
|
+
"WATCH_TIMEOUT",
|
|
2457
|
+
"TRANSACTION_FAILED",
|
|
2458
|
+
"TRANSACTION_SUBMISSION_UNKNOWN",
|
|
2459
|
+
"TRANSACTION_STATUS_UNKNOWN"
|
|
2460
|
+
]);
|
|
2461
|
+
var cashSourceRecoveryJsonShape = {
|
|
2462
|
+
amount: nonNegativeBigintString,
|
|
2463
|
+
requestId: zod.z.string().optional(),
|
|
2464
|
+
txHashes: zod.z.array(zod.z.string()),
|
|
2465
|
+
transactions: relayTransactionsJsonSchema.optional()
|
|
2466
|
+
};
|
|
2467
|
+
var cashErrorRecoveryJsonSchema = zod.z.discriminatedUnion("kind", [
|
|
2468
|
+
zod.z.object({
|
|
2469
|
+
...cashSourceRecoveryJsonShape,
|
|
2470
|
+
kind: zod.z.literal("retry-base-usdc-cashout")
|
|
2471
|
+
}).strict(),
|
|
2472
|
+
zod.z.object({
|
|
2473
|
+
...cashSourceRecoveryJsonShape,
|
|
2474
|
+
kind: zod.z.literal("inspect-base-cashout-transaction"),
|
|
2475
|
+
depositTxHash: zod.z.string()
|
|
2476
|
+
}).strict(),
|
|
2477
|
+
zod.z.object({
|
|
2478
|
+
...cashSourceRecoveryJsonShape,
|
|
2479
|
+
kind: zod.z.literal("inspect-base-cashout-submission"),
|
|
2480
|
+
depositor: zod.z.string()
|
|
2481
|
+
}).strict(),
|
|
2482
|
+
zod.z.object({
|
|
2483
|
+
kind: zod.z.literal("inspect-relay-route"),
|
|
2484
|
+
requestId: zod.z.string().optional(),
|
|
2485
|
+
txHashes: zod.z.array(zod.z.string()),
|
|
2486
|
+
transactions: relayTransactionsJsonSchema.optional()
|
|
2487
|
+
}).strict(),
|
|
2488
|
+
zod.z.object({
|
|
2489
|
+
kind: zod.z.literal("inspect-base-operation-submission"),
|
|
2490
|
+
operation: zod.z.string()
|
|
2491
|
+
}).strict(),
|
|
2492
|
+
zod.z.object({
|
|
2493
|
+
kind: zod.z.literal("inspect-base-transaction"),
|
|
2494
|
+
transactionHash: zod.z.string(),
|
|
2495
|
+
operation: zod.z.string()
|
|
2496
|
+
}).strict()
|
|
2497
|
+
]);
|
|
1836
2498
|
var cashErrorJsonSchema = zod.z.object({
|
|
1837
|
-
code: zod.z.
|
|
2499
|
+
code: zod.z.enum(CASH_ERROR_CODES),
|
|
1838
2500
|
message: zod.z.string(),
|
|
1839
2501
|
retryable: zod.z.boolean(),
|
|
1840
|
-
remediation: zod.z.string()
|
|
1841
|
-
|
|
2502
|
+
remediation: zod.z.string(),
|
|
2503
|
+
recovery: cashErrorRecoveryJsonSchema.optional()
|
|
2504
|
+
}).strict();
|
|
1842
2505
|
|
|
1843
2506
|
// src/codecs/json.ts
|
|
1844
2507
|
function omitUndefined(obj) {
|
|
@@ -1869,35 +2532,38 @@ function fillToJson(fill) {
|
|
|
1869
2532
|
});
|
|
1870
2533
|
}
|
|
1871
2534
|
function fillFromJson(json) {
|
|
2535
|
+
const parsed = cashFillJsonSchema.parse(json);
|
|
1872
2536
|
return omitUndefined({
|
|
1873
|
-
...
|
|
1874
|
-
amount: BigInt(
|
|
1875
|
-
conversionRate:
|
|
1876
|
-
releasedAmount:
|
|
2537
|
+
...parsed,
|
|
2538
|
+
amount: BigInt(parsed.amount),
|
|
2539
|
+
conversionRate: parsed.conversionRate !== void 0 ? BigInt(parsed.conversionRate) : void 0,
|
|
2540
|
+
releasedAmount: parsed.releasedAmount !== void 0 ? BigInt(parsed.releasedAmount) : void 0
|
|
1877
2541
|
});
|
|
1878
2542
|
}
|
|
1879
2543
|
function orderToJson(order) {
|
|
1880
|
-
return
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2544
|
+
return cashOrderJsonSchema.parse(
|
|
2545
|
+
omitUndefined({
|
|
2546
|
+
depositId: order.depositId,
|
|
2547
|
+
state: order.state,
|
|
2548
|
+
fills: order.fills.map(fillToJson),
|
|
2549
|
+
totalAmount: order.totalAmount.toString(),
|
|
2550
|
+
filledAmount: order.filledAmount.toString(),
|
|
2551
|
+
pendingAmount: order.pendingAmount.toString(),
|
|
2552
|
+
returnedAmount: order.returnedAmount.toString(),
|
|
2553
|
+
nextActions: order.nextActions,
|
|
2554
|
+
primaryIntentHash: order.primaryIntentHash,
|
|
2555
|
+
matchedAt: order.matchedAt,
|
|
2556
|
+
deliveredAt: order.deliveredAt,
|
|
2557
|
+
updatedAt: order.updatedAt,
|
|
2558
|
+
intentCount: order.intentCount,
|
|
2559
|
+
payouts: order.payouts?.map(
|
|
2560
|
+
(p) => omitUndefined({ ...p, pricing: omitUndefined({ ...p.pricing }) })
|
|
2561
|
+
),
|
|
2562
|
+
successRateBps: order.successRateBps,
|
|
2563
|
+
isInFlight: order.isInFlight,
|
|
2564
|
+
withdrawn: order.withdrawn
|
|
2565
|
+
})
|
|
2566
|
+
);
|
|
1901
2567
|
}
|
|
1902
2568
|
function orderFromJson(json) {
|
|
1903
2569
|
const parsed = cashOrderJsonSchema.parse(json);
|
|
@@ -1923,6 +2589,7 @@ function estimateToJson(estimate) {
|
|
|
1923
2589
|
inputAmount: estimate.source.relayQuote.inputAmount.toString(),
|
|
1924
2590
|
outputAmount: estimate.source.relayQuote.outputAmount.toString(),
|
|
1925
2591
|
txs: estimate.source.relayQuote.txs.map(preparedTxToJson),
|
|
2592
|
+
...estimate.source.relayQuote.fees !== void 0 ? { fees: sanitizeRelayValue(estimate.source.relayQuote.fees) } : {},
|
|
1926
2593
|
raw: sanitizeRelayQuoteRaw(estimate.source.relayQuote.raw)
|
|
1927
2594
|
}
|
|
1928
2595
|
} : void 0
|
|
@@ -1941,11 +2608,108 @@ function estimateFromJson(json) {
|
|
|
1941
2608
|
...parsed.source.relayQuote,
|
|
1942
2609
|
inputAmount: BigInt(parsed.source.relayQuote.inputAmount),
|
|
1943
2610
|
outputAmount: BigInt(parsed.source.relayQuote.outputAmount),
|
|
1944
|
-
txs: parsed.source.relayQuote.txs.map(preparedTxFromJson)
|
|
2611
|
+
txs: parsed.source.relayQuote.txs.map(preparedTxFromJson),
|
|
2612
|
+
...parsed.source.relayQuote.fees !== void 0 ? { fees: restoreRelayValue(parsed.source.relayQuote.fees) } : {},
|
|
2613
|
+
raw: restoreRelayQuoteRaw(parsed.source.relayQuote.raw)
|
|
1945
2614
|
}
|
|
1946
2615
|
} : void 0
|
|
1947
2616
|
});
|
|
1948
2617
|
}
|
|
2618
|
+
function cashAssetFromJson(asset) {
|
|
2619
|
+
return {
|
|
2620
|
+
chainId: asset.chainId,
|
|
2621
|
+
address: asset.address,
|
|
2622
|
+
symbol: asset.symbol,
|
|
2623
|
+
decimals: asset.decimals,
|
|
2624
|
+
...asset.name !== void 0 ? { name: asset.name } : {},
|
|
2625
|
+
...asset.isNative !== void 0 ? { isNative: asset.isNative } : {}
|
|
2626
|
+
};
|
|
2627
|
+
}
|
|
2628
|
+
function relayQuoteToJson(quote) {
|
|
2629
|
+
return relayQuoteJsonSchema.parse({
|
|
2630
|
+
...quote.requestId !== void 0 ? { requestId: quote.requestId } : {},
|
|
2631
|
+
source: quote.source,
|
|
2632
|
+
destination: quote.destination,
|
|
2633
|
+
inputAmount: quote.inputAmount.toString(),
|
|
2634
|
+
outputAmount: quote.outputAmount.toString(),
|
|
2635
|
+
...quote.rate !== void 0 ? { rate: quote.rate } : {},
|
|
2636
|
+
...quote.timeEstimateSeconds !== void 0 ? { timeEstimateSeconds: quote.timeEstimateSeconds } : {},
|
|
2637
|
+
...quote.fees !== void 0 ? { fees: sanitizeRelayValue(quote.fees) } : {},
|
|
2638
|
+
txs: quote.txs.map(preparedTxToJson),
|
|
2639
|
+
raw: sanitizeRelayQuoteRaw(quote.raw)
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
function relayQuoteFromJson(json) {
|
|
2643
|
+
const parsed = relayQuoteJsonSchema.parse(json);
|
|
2644
|
+
return {
|
|
2645
|
+
...parsed.requestId !== void 0 ? { requestId: parsed.requestId } : {},
|
|
2646
|
+
source: cashAssetFromJson(parsed.source),
|
|
2647
|
+
destination: cashAssetFromJson(parsed.destination),
|
|
2648
|
+
inputAmount: BigInt(parsed.inputAmount),
|
|
2649
|
+
outputAmount: BigInt(parsed.outputAmount),
|
|
2650
|
+
...parsed.rate !== void 0 ? { rate: parsed.rate } : {},
|
|
2651
|
+
...parsed.timeEstimateSeconds !== void 0 ? { timeEstimateSeconds: parsed.timeEstimateSeconds } : {},
|
|
2652
|
+
...parsed.fees !== void 0 ? { fees: restoreRelayValue(parsed.fees) } : {},
|
|
2653
|
+
txs: parsed.txs.map(preparedTxFromJson),
|
|
2654
|
+
raw: restoreRelayQuoteRaw(parsed.raw)
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
function sourceCapabilitiesToJson(capabilities) {
|
|
2658
|
+
return cashSourceCapabilitiesJsonSchema.parse(capabilities);
|
|
2659
|
+
}
|
|
2660
|
+
function sourceCapabilitiesFromJson(json) {
|
|
2661
|
+
const parsed = cashSourceCapabilitiesJsonSchema.parse(json);
|
|
2662
|
+
return {
|
|
2663
|
+
destination: cashAssetFromJson(parsed.destination),
|
|
2664
|
+
chains: parsed.chains.map((chain) => ({
|
|
2665
|
+
id: chain.id,
|
|
2666
|
+
name: chain.name,
|
|
2667
|
+
displayName: chain.displayName,
|
|
2668
|
+
disabled: chain.disabled,
|
|
2669
|
+
depositEnabled: chain.depositEnabled,
|
|
2670
|
+
blockProductionLagging: chain.blockProductionLagging,
|
|
2671
|
+
...chain.vmType !== void 0 ? { vmType: chain.vmType } : {},
|
|
2672
|
+
tokens: chain.tokens.map(cashAssetFromJson)
|
|
2673
|
+
})),
|
|
2674
|
+
source: parsed.source,
|
|
2675
|
+
asOf: parsed.asOf
|
|
2676
|
+
};
|
|
2677
|
+
}
|
|
2678
|
+
function relayStatusToJson(status) {
|
|
2679
|
+
return relayStatusJsonSchema.parse({ ...status, raw: sanitizeRelayValue(status.raw) });
|
|
2680
|
+
}
|
|
2681
|
+
function relayStatusFromJson(json) {
|
|
2682
|
+
const parsed = relayStatusJsonSchema.parse(json);
|
|
2683
|
+
return {
|
|
2684
|
+
requestId: parsed.requestId,
|
|
2685
|
+
status: parsed.status,
|
|
2686
|
+
...parsed.details !== void 0 ? { details: parsed.details } : {},
|
|
2687
|
+
inTxHashes: parsed.inTxHashes,
|
|
2688
|
+
txHashes: parsed.txHashes,
|
|
2689
|
+
...parsed.updatedAt !== void 0 ? { updatedAt: parsed.updatedAt } : {},
|
|
2690
|
+
...parsed.originChainId !== void 0 ? { originChainId: parsed.originChainId } : {},
|
|
2691
|
+
...parsed.destinationChainId !== void 0 ? { destinationChainId: parsed.destinationChainId } : {},
|
|
2692
|
+
...parsed.quoteCreatedAt !== void 0 ? { quoteCreatedAt: parsed.quoteCreatedAt } : {},
|
|
2693
|
+
raw: restoreRelayValue(parsed.raw)
|
|
2694
|
+
};
|
|
2695
|
+
}
|
|
2696
|
+
function relayExecutionResultToJson(result) {
|
|
2697
|
+
return relayExecutionResultJsonSchema.parse({
|
|
2698
|
+
...result.requestId !== void 0 ? { requestId: result.requestId } : {},
|
|
2699
|
+
txHashes: result.txHashes,
|
|
2700
|
+
...result.transactions !== void 0 ? { transactions: result.transactions } : {},
|
|
2701
|
+
quote: sanitizeRelayQuoteRaw(result.quote)
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
function relayExecutionResultFromJson(json) {
|
|
2705
|
+
const parsed = relayExecutionResultJsonSchema.parse(json);
|
|
2706
|
+
return {
|
|
2707
|
+
...parsed.requestId !== void 0 ? { requestId: parsed.requestId } : {},
|
|
2708
|
+
txHashes: parsed.txHashes,
|
|
2709
|
+
...parsed.transactions !== void 0 ? { transactions: parsed.transactions } : {},
|
|
2710
|
+
quote: restoreRelayQuoteRaw(parsed.quote)
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
1949
2713
|
function preparedTxToJson(tx) {
|
|
1950
2714
|
return { to: tx.to, data: tx.data, value: tx.value.toString(), chainId: tx.chainId };
|
|
1951
2715
|
}
|
|
@@ -2064,6 +2828,69 @@ function capabilitiesFromJson(json) {
|
|
|
2064
2828
|
}
|
|
2065
2829
|
};
|
|
2066
2830
|
}
|
|
2831
|
+
function cashErrorToJson(error) {
|
|
2832
|
+
return cashErrorJsonSchema.parse({
|
|
2833
|
+
code: error.code,
|
|
2834
|
+
message: error.message,
|
|
2835
|
+
retryable: error.retryable,
|
|
2836
|
+
remediation: error.remediation,
|
|
2837
|
+
...error.recovery ? { recovery: error.recovery } : {}
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
function cashErrorFromJson(json) {
|
|
2841
|
+
const parsed = cashErrorJsonSchema.parse(json);
|
|
2842
|
+
let recovery;
|
|
2843
|
+
if (parsed.recovery) {
|
|
2844
|
+
if (parsed.recovery.kind === "inspect-base-transaction") {
|
|
2845
|
+
recovery = {
|
|
2846
|
+
kind: parsed.recovery.kind,
|
|
2847
|
+
transactionHash: parsed.recovery.transactionHash,
|
|
2848
|
+
operation: parsed.recovery.operation
|
|
2849
|
+
};
|
|
2850
|
+
} else if (parsed.recovery.kind === "inspect-base-operation-submission") {
|
|
2851
|
+
recovery = {
|
|
2852
|
+
kind: parsed.recovery.kind,
|
|
2853
|
+
operation: parsed.recovery.operation
|
|
2854
|
+
};
|
|
2855
|
+
} else if (parsed.recovery.kind === "inspect-relay-route") {
|
|
2856
|
+
recovery = {
|
|
2857
|
+
kind: parsed.recovery.kind,
|
|
2858
|
+
txHashes: parsed.recovery.txHashes,
|
|
2859
|
+
...parsed.recovery.requestId !== void 0 ? { requestId: parsed.recovery.requestId } : {},
|
|
2860
|
+
...parsed.recovery.transactions !== void 0 ? { transactions: parsed.recovery.transactions } : {}
|
|
2861
|
+
};
|
|
2862
|
+
} else {
|
|
2863
|
+
const common = {
|
|
2864
|
+
amount: parsed.recovery.amount,
|
|
2865
|
+
txHashes: parsed.recovery.txHashes,
|
|
2866
|
+
...parsed.recovery.requestId !== void 0 ? { requestId: parsed.recovery.requestId } : {},
|
|
2867
|
+
...parsed.recovery.transactions !== void 0 ? { transactions: parsed.recovery.transactions } : {}
|
|
2868
|
+
};
|
|
2869
|
+
if (parsed.recovery.kind === "retry-base-usdc-cashout") {
|
|
2870
|
+
recovery = { ...common, kind: parsed.recovery.kind };
|
|
2871
|
+
} else if (parsed.recovery.kind === "inspect-base-cashout-submission") {
|
|
2872
|
+
recovery = {
|
|
2873
|
+
...common,
|
|
2874
|
+
kind: parsed.recovery.kind,
|
|
2875
|
+
depositor: parsed.recovery.depositor
|
|
2876
|
+
};
|
|
2877
|
+
} else {
|
|
2878
|
+
recovery = {
|
|
2879
|
+
...common,
|
|
2880
|
+
kind: parsed.recovery.kind,
|
|
2881
|
+
depositTxHash: parsed.recovery.depositTxHash
|
|
2882
|
+
};
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
return new CashError({
|
|
2887
|
+
code: parsed.code,
|
|
2888
|
+
message: parsed.message,
|
|
2889
|
+
retryable: parsed.retryable,
|
|
2890
|
+
remediation: parsed.remediation,
|
|
2891
|
+
...recovery ? { recovery } : {}
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2067
2894
|
|
|
2068
2895
|
exports.BASE_CHAIN_ID = BASE_CHAIN_ID;
|
|
2069
2896
|
exports.BASE_USDC_ADDRESS = BASE_USDC_ADDRESS;
|
|
@@ -2086,9 +2913,14 @@ exports.buyerProfileFromJson = buyerProfileFromJson;
|
|
|
2086
2913
|
exports.buyerProfileToJson = buyerProfileToJson;
|
|
2087
2914
|
exports.capabilitiesFromJson = capabilitiesFromJson;
|
|
2088
2915
|
exports.capabilitiesToJson = capabilitiesToJson;
|
|
2916
|
+
exports.cashAssetJsonSchema = cashAssetJsonSchema;
|
|
2089
2917
|
exports.cashBuyerProfileJsonSchema = cashBuyerProfileJsonSchema;
|
|
2090
2918
|
exports.cashCapabilitiesJsonSchema = cashCapabilitiesJsonSchema;
|
|
2919
|
+
exports.cashChainJsonSchema = cashChainJsonSchema;
|
|
2920
|
+
exports.cashErrorFromJson = cashErrorFromJson;
|
|
2091
2921
|
exports.cashErrorJsonSchema = cashErrorJsonSchema;
|
|
2922
|
+
exports.cashErrorRecoveryJsonSchema = cashErrorRecoveryJsonSchema;
|
|
2923
|
+
exports.cashErrorToJson = cashErrorToJson;
|
|
2092
2924
|
exports.cashEstimateJsonSchema = cashEstimateJsonSchema;
|
|
2093
2925
|
exports.cashFillJsonSchema = cashFillJsonSchema;
|
|
2094
2926
|
exports.cashNextActionSchema = cashNextActionSchema;
|
|
@@ -2097,6 +2929,7 @@ exports.cashOrderStateSchema = cashOrderStateSchema;
|
|
|
2097
2929
|
exports.cashPayoutInfoJsonSchema = cashPayoutInfoJsonSchema;
|
|
2098
2930
|
exports.cashPayoutPricingJsonSchema = cashPayoutPricingJsonSchema;
|
|
2099
2931
|
exports.cashPreparedStepJsonSchema = cashPreparedStepJsonSchema;
|
|
2932
|
+
exports.cashSourceCapabilitiesJsonSchema = cashSourceCapabilitiesJsonSchema;
|
|
2100
2933
|
exports.cashoutResultFromJson = cashoutResultFromJson;
|
|
2101
2934
|
exports.cashoutResultJsonSchema = cashoutResultJsonSchema;
|
|
2102
2935
|
exports.cashoutResultToJson = cashoutResultToJson;
|
|
@@ -2118,6 +2951,7 @@ exports.intentStatusSchema = intentStatusSchema;
|
|
|
2118
2951
|
exports.isCashError = isCashError;
|
|
2119
2952
|
exports.isFillLive = isFillLive;
|
|
2120
2953
|
exports.isMarketRateSupported = isMarketRateSupported;
|
|
2954
|
+
exports.nonNegativeBigintString = nonNegativeBigintString;
|
|
2121
2955
|
exports.orderFromJson = orderFromJson;
|
|
2122
2956
|
exports.orderToJson = orderToJson;
|
|
2123
2957
|
exports.parseCompositeDepositId = parseCompositeDepositId;
|
|
@@ -2131,7 +2965,20 @@ exports.preparedTransactionJsonSchema = preparedTransactionJsonSchema;
|
|
|
2131
2965
|
exports.preparedTxFromJson = preparedTxFromJson;
|
|
2132
2966
|
exports.preparedTxToJson = preparedTxToJson;
|
|
2133
2967
|
exports.rateToNumber = rateToNumber;
|
|
2968
|
+
exports.relayExecutionResultFromJson = relayExecutionResultFromJson;
|
|
2969
|
+
exports.relayExecutionResultJsonSchema = relayExecutionResultJsonSchema;
|
|
2970
|
+
exports.relayExecutionResultToJson = relayExecutionResultToJson;
|
|
2971
|
+
exports.relayQuoteFromJson = relayQuoteFromJson;
|
|
2972
|
+
exports.relayQuoteJsonSchema = relayQuoteJsonSchema;
|
|
2973
|
+
exports.relayQuoteToJson = relayQuoteToJson;
|
|
2974
|
+
exports.relayStatusFromJson = relayStatusFromJson;
|
|
2975
|
+
exports.relayStatusJsonSchema = relayStatusJsonSchema;
|
|
2976
|
+
exports.relayStatusToJson = relayStatusToJson;
|
|
2977
|
+
exports.relayTransactionJsonSchema = relayTransactionJsonSchema;
|
|
2978
|
+
exports.relayTransactionsJsonSchema = relayTransactionsJsonSchema;
|
|
2134
2979
|
exports.resolveCashDepositId = resolveCashDepositId;
|
|
2980
|
+
exports.sourceCapabilitiesFromJson = sourceCapabilitiesFromJson;
|
|
2981
|
+
exports.sourceCapabilitiesToJson = sourceCapabilitiesToJson;
|
|
2135
2982
|
exports.topUpResultFromJson = topUpResultFromJson;
|
|
2136
2983
|
exports.topUpResultJsonSchema = topUpResultJsonSchema;
|
|
2137
2984
|
exports.topUpResultToJson = topUpResultToJson;
|
|
@@ -2140,5 +2987,3 @@ exports.withExplain = withExplain;
|
|
|
2140
2987
|
exports.withdrawResultFromJson = withdrawResultFromJson;
|
|
2141
2988
|
exports.withdrawResultJsonSchema = withdrawResultJsonSchema;
|
|
2142
2989
|
exports.withdrawResultToJson = withdrawResultToJson;
|
|
2143
|
-
//# sourceMappingURL=index.cjs.map
|
|
2144
|
-
//# sourceMappingURL=index.cjs.map
|