@stelis/say-ur-intent 0.0.0 → 0.0.2
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/README.md +4 -39
- package/dist/adapters/adapterLifecycleValidators.js +7 -0
- package/dist/adapters/adapterPromptSurfaces.js +71 -0
- package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +175 -0
- package/dist/adapters/deepbook/deepbookQuotePolicy.js +112 -0
- package/dist/adapters/deepbook/deepbookReviewEvidence.js +507 -0
- package/dist/adapters/deepbook/deepbookReviewLifecycle.js +85 -0
- package/dist/adapters/deepbook/deepbookSwapIntent.js +79 -0
- package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +269 -0
- package/dist/adapters/flowx/flowxSwapHumanReviewProducer.js +176 -0
- package/dist/adapters/flowx/flowxSwapIntent.js +79 -0
- package/dist/adapters/flowx/flowxSwapQuotePolicy.js +104 -0
- package/dist/adapters/flowx/flowxSwapReviewEvidence.js +468 -0
- package/dist/adapters/flowx/flowxSwapReviewLifecycle.js +85 -0
- package/dist/adapters/flowx/flowxSwapTransactionMaterialProducer.js +362 -0
- package/dist/adapters/intentPlanFactories.js +59 -0
- package/dist/adapters/reviewAdapters.js +81 -0
- package/dist/core/action/adapterLifecycleValidation.js +12 -0
- package/dist/core/action/forbiddenFields.js +43 -0
- package/dist/core/action/humanReadableReviewEvidence.js +203 -0
- package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
- package/dist/core/action/ptbVisualizationProducer.js +66 -0
- package/dist/core/action/reviewCheckResults.js +6 -0
- package/dist/core/action/reviewStateValidation.js +11 -0
- package/dist/core/action/reviewTimeSimulationEvidence.js +471 -0
- package/dist/core/action/schemas.js +529 -0
- package/dist/core/action/signableAdapterContract.js +993 -0
- package/dist/core/action/swapHumanReadableReviewProjection.js +124 -0
- package/dist/core/action/swapQuotePolicyEvidence.js +278 -0
- package/dist/core/action/transactionObjectOwnershipEvidence.js +247 -0
- package/dist/core/action/transactionObjectOwnershipProducer.js +329 -0
- package/dist/core/action/types.js +35 -0
- package/dist/core/action/walletReviewContractAssembler.js +282 -0
- package/dist/core/activity/activityStore.js +15 -0
- package/dist/core/activity/localDataService.js +258 -0
- package/dist/core/activity/localDataTypes.js +11 -0
- package/dist/core/activity/localDataValidation.js +396 -0
- package/dist/core/activity/schemaVersion.js +1 -0
- package/dist/core/activity/sqliteActivityStore.js +820 -0
- package/dist/core/activity/sqliteActivityStoreRows.js +430 -0
- package/dist/core/activity/sqliteActivityStoreSchema.js +258 -0
- package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
- package/dist/core/activity/suiFunctionTarget.js +43 -0
- package/dist/core/activity/transactionActivityAccountEffects.js +189 -0
- package/dist/core/activity/transactionActivityAnalysis.js +295 -0
- package/dist/core/activity/transactionActivityClassifier.js +306 -0
- package/dist/core/activity/transactionActivityDetails.js +229 -0
- package/dist/core/activity/transactionActivityProtocolRules.js +218 -0
- package/dist/core/activity/transactionActivityScanPolicy.js +170 -0
- package/dist/core/activity/transactionActivityService.js +379 -0
- package/dist/core/activity/transactionActivityTypes.js +18 -0
- package/dist/core/eventlog/sink.js +35 -0
- package/dist/core/evidence/settlementFamilies.js +87 -0
- package/dist/core/evidence/userAnswerUse.js +1 -0
- package/dist/core/numeric/rawU64.js +63 -0
- package/dist/core/preferences/preferencesStore.js +26 -0
- package/dist/core/preferences/sqlitePreferencesRepository.js +136 -0
- package/dist/core/proposal/externalProposalReview.js +347 -0
- package/dist/core/proposal/schemas.js +208 -0
- package/dist/core/proposal/types.js +35 -0
- package/dist/core/read/amounts.js +14 -0
- package/dist/core/read/coinMetadata.js +60 -0
- package/dist/core/read/deepbookRawQuoteClient.js +86 -0
- package/dist/core/read/deepbookReadHelpers.js +265 -0
- package/dist/core/read/deepbookRegistry.js +133 -0
- package/dist/core/read/flowxQuoteClient.js +117 -0
- package/dist/core/read/flowxReadHelpers.js +145 -0
- package/dist/core/read/flowxRegistry.js +174 -0
- package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
- package/dist/core/read/readResponseGuidance.js +451 -0
- package/dist/core/read/readService.js +1164 -0
- package/dist/core/read/readServiceTypes.js +59 -0
- package/dist/core/read/settlementParityFormatting.js +82 -0
- package/dist/core/read/walletReadHelpers.js +99 -0
- package/dist/core/review/reviewChecks.js +54 -0
- package/dist/core/review/reviewComputation.js +38 -0
- package/dist/core/review/reviewComputationResult.js +87 -0
- package/dist/core/session/localSession.js +31 -0
- package/dist/core/session/privateReviewArtifacts.js +73 -0
- package/dist/core/session/sessionErrors.js +9 -0
- package/dist/core/session/sessionStore.js +821 -0
- package/dist/core/session/settingsSession.js +1 -0
- package/dist/core/session/settingsSessions.js +43 -0
- package/dist/core/session/status.js +86 -0
- package/dist/core/session/transactionMaterialStore.js +205 -0
- package/dist/core/session/wait.js +102 -0
- package/dist/core/session/walletIdentity.js +103 -0
- package/dist/core/session/walletIdentitySessions.js +189 -0
- package/dist/core/suiAddress.js +18 -0
- package/dist/core/suiEndpoint.js +72 -0
- package/dist/mcp/activeAccountResponse.js +24 -0
- package/dist/mcp/prompts.js +146 -0
- package/dist/mcp/registerTool.js +19 -0
- package/dist/mcp/resources.js +72 -0
- package/dist/mcp/responseGuidance.js +381 -0
- package/dist/mcp/result.js +17 -0
- package/dist/mcp/schemas.js +8 -0
- package/dist/mcp/server.js +30 -0
- package/dist/mcp/serverInfo.js +123 -0
- package/dist/mcp/toolErrors.js +105 -0
- package/dist/mcp/toolNames.js +50 -0
- package/dist/mcp/tools/account/index.js +44 -0
- package/dist/mcp/tools/action/prepareSuiActionReview.js +120 -0
- package/dist/mcp/tools/read/commonSchemas.js +43 -0
- package/dist/mcp/tools/read/deepbookReadTools.js +453 -0
- package/dist/mcp/tools/read/flowxReadTools.js +135 -0
- package/dist/mcp/tools/read/index.js +16 -0
- package/dist/mcp/tools/read/readToolHelpers.js +68 -0
- package/dist/mcp/tools/read/reviewActivityTools.js +176 -0
- package/dist/mcp/tools/read/serverStatusTools.js +103 -0
- package/dist/mcp/tools/read/transactionActivityOutput.js +300 -0
- package/dist/mcp/tools/read/transactionActivityTools.js +544 -0
- package/dist/mcp/tools/read/walletReadTools.js +733 -0
- package/dist/mcp/tools/session/executionResultTools.js +92 -0
- package/dist/mcp/tools/session/index.js +8 -0
- package/dist/mcp/tools/session/shared.js +79 -0
- package/dist/mcp/tools/session/statusTools.js +134 -0
- package/dist/mcp/tools/session/walletIdentityTools.js +119 -0
- package/dist/mcp/tools/settings/index.js +64 -0
- package/dist/review-app/analysis.css +1 -0
- package/dist/review-app/analysis.js +1 -0
- package/dist/review-app/arc-BjIacwQm.js +1 -0
- package/dist/review-app/architecture-U656AL7Q-aSB9x1OK.js +1 -0
- package/dist/review-app/architectureDiagram-VXUJARFQ-C5W6re2I.js +36 -0
- package/dist/review-app/array-BmXUUrU6.js +1 -0
- package/dist/review-app/blockDiagram-VD42YOAC-20MLNcUm.js +122 -0
- package/dist/review-app/c4Diagram-YG6GDRKO-BZXRrcck.js +10 -0
- package/dist/review-app/channel-lk2p_CUu.js +1 -0
- package/dist/review-app/chunk-4BX2VUAB-BPITOdjX.js +1 -0
- package/dist/review-app/chunk-55IACEB6-Dz-pyw5k.js +1 -0
- package/dist/review-app/chunk-76Q3JFCE-cK_X1P_l.js +1 -0
- package/dist/review-app/chunk-ABZYJK2D-Dt4W53JI.js +81 -0
- package/dist/review-app/chunk-ATLVNIR6-fZHLXURb.js +1 -0
- package/dist/review-app/chunk-B4BG7PRW-BbgcjusC.js +165 -0
- package/dist/review-app/chunk-BJD4TVEz.js +1 -0
- package/dist/review-app/chunk-CVBHYZKI-CViawAKX.js +1 -0
- package/dist/review-app/chunk-DI55MBZ5-C5aoul-d.js +220 -0
- package/dist/review-app/chunk-FMBD7UC4-Chxmw62A.js +15 -0
- package/dist/review-app/chunk-FPAJGGOC-DDHjQ09H.js +80 -0
- package/dist/review-app/chunk-FWNWRKHM-CVVQUptk.js +1 -0
- package/dist/review-app/chunk-HN2XXSSU-yzNpjaSZ.js +1 -0
- package/dist/review-app/chunk-JA3XYJ7Z-C5ZJdU01.js +70 -0
- package/dist/review-app/chunk-JZLCHNYA-BBST4Cnk.js +54 -0
- package/dist/review-app/chunk-LBM3YZW2-CdwAPuHr.js +1 -0
- package/dist/review-app/chunk-LHMN2FUI-BtB5uDcp.js +1 -0
- package/dist/review-app/chunk-O7ZBX7Z2-pxdK4Sa3.js +1 -0
- package/dist/review-app/chunk-QN33PNHL-CbVv3uGK.js +1 -0
- package/dist/review-app/chunk-QXUST7PY-DKM2-t2c.js +7 -0
- package/dist/review-app/chunk-QZHKN3VN-C5ni2pN_.js +1 -0
- package/dist/review-app/chunk-S3R3BYOJ-BWvOhDs0.js +2 -0
- package/dist/review-app/chunk-S6J4BHB3-D9Fk0YeD.js +1 -0
- package/dist/review-app/chunk-T53DSG4Q-C1qEyzyV.js +1 -0
- package/dist/review-app/chunk-TZMSLE5B-B--7eU69.js +1 -0
- package/dist/review-app/classDiagram-2ON5EDUG-DlL1m2bp.js +1 -0
- package/dist/review-app/classDiagram-v2-WZHVMYZB-FXRskT1j.js +1 -0
- package/dist/review-app/clone-BZZb7gpZ.js +1 -0
- package/dist/review-app/cose-bilkent-S5V4N54A-CRIb8XEO.js +1 -0
- package/dist/review-app/cytoscape.esm-C7jYqDP5.js +321 -0
- package/dist/review-app/dagre-6UL2VRFP-FNCAXbdE.js +4 -0
- package/dist/review-app/dagre-Be46QtUd.js +1 -0
- package/dist/review-app/defaultLocale-BaWNtAUL.js +1 -0
- package/dist/review-app/diagram-PSM6KHXK-ylLWjiNM.js +24 -0
- package/dist/review-app/diagram-QEK2KX5R-BCDcESxs.js +43 -0
- package/dist/review-app/diagram-S2PKOQOG-Vdrc-vrO.js +24 -0
- package/dist/review-app/dist-WPc74x_f.js +1 -0
- package/dist/review-app/erDiagram-Q2GNP2WA-E5ZsUbDF.js +60 -0
- package/dist/review-app/flatten-DHf9IeNI.js +1 -0
- package/dist/review-app/flowDiagram-NV44I4VS-DBSQuj6x.js +162 -0
- package/dist/review-app/ganttDiagram-LVOFAZNH-CKUOsqwl.js +267 -0
- package/dist/review-app/gitGraph-F6HP7TQM-DsAD6qK1.js +1 -0
- package/dist/review-app/gitGraphDiagram-NY62KEGX-BCeIMWdl.js +65 -0
- package/dist/review-app/graphlib-CiX5CXxR.js +1 -0
- package/dist/review-app/http-DMvwuuFk.js +1 -0
- package/dist/review-app/identity-DY8PXc6t.js +1 -0
- package/dist/review-app/info-NVLQJR56-Dlx1nZic.js +1 -0
- package/dist/review-app/infoDiagram-F6ZHWCRC-CAuANIrz.js +2 -0
- package/dist/review-app/init-BvqephKz.js +1 -0
- package/dist/review-app/journeyDiagram-XKPGCS4Q-C-Z9phnx.js +139 -0
- package/dist/review-app/kanban-definition-3W4ZIXB7-DufgZABq.js +89 -0
- package/dist/review-app/katex-B-Z-NXXN.js +257 -0
- package/dist/review-app/line-DiIv3Jgw.js +1 -0
- package/dist/review-app/linear-Cv-UPvo1.js +1 -0
- package/dist/review-app/math-kmyYrkHL.js +1 -0
- package/dist/review-app/mermaid-parser.core-DkwUYTPl.js +4 -0
- package/dist/review-app/mindmap-definition-VGOIOE7T-TM_CqdmV.js +68 -0
- package/dist/review-app/ordinal-BliTlkoG.js +1 -0
- package/dist/review-app/packet-BFZMPI3H-DqbnU92v.js +1 -0
- package/dist/review-app/path-AEo9W6mQ.js +1 -0
- package/dist/review-app/pie-7BOR55EZ-LJzaLkgr.js +1 -0
- package/dist/review-app/pieDiagram-ADFJNKIX-BAs8OfRS.js +30 -0
- package/dist/review-app/quadrantDiagram-AYHSOK5B-CyUDZP5S.js +7 -0
- package/dist/review-app/radar-NHE76QYJ-DBpHc8_Y.js +1 -0
- package/dist/review-app/reduce-B-HuPpdd.js +1 -0
- package/dist/review-app/requirementDiagram-UZGBJVZJ-BEHix78P.js +64 -0
- package/dist/review-app/review.css +1 -0
- package/dist/review-app/review.js +43 -0
- package/dist/review-app/sankeyDiagram-TZEHDZUN-B2bKbmsm.js +10 -0
- package/dist/review-app/sequenceDiagram-WL72ISMW-DVLOORFJ.js +145 -0
- package/dist/review-app/settings.css +1 -0
- package/dist/review-app/settings.js +1 -0
- package/dist/review-app/src-Buml7cM5.js +1 -0
- package/dist/review-app/stateDiagram-FKZM4ZOC-sFGGp2kV.js +1 -0
- package/dist/review-app/stateDiagram-v2-4FDKWEC3-BHfCF4dX.js +1 -0
- package/dist/review-app/timeline-definition-IT6M3QCI-BESnBijC.js +61 -0
- package/dist/review-app/treemap-KMMF4GRG-wnVLBDeQ.js +1 -0
- package/dist/review-app/walletStatus-CcojOdGy.js +7 -0
- package/dist/review-app/xychartDiagram-PRI3JC2R-BGWVfCx4.js +7 -0
- package/dist/review-server/assets.js +48 -0
- package/dist/review-server/html.js +66 -0
- package/dist/review-server/http.js +47 -0
- package/dist/review-server/middleware/hostOrigin.js +48 -0
- package/dist/review-server/middleware/reviewToken.js +7 -0
- package/dist/review-server/reviewServerPolicy.js +10 -0
- package/dist/review-server/server.js +568 -0
- package/dist/review-server/settingsApi.js +182 -0
- package/dist/review-server/walletIdentityResponse.js +13 -0
- package/dist/runtime/config.js +103 -0
- package/dist/runtime/localSettingsService.js +198 -0
- package/dist/runtime/logger.js +50 -0
- package/dist/runtime/reviewServerAcquire.js +128 -0
- package/dist/runtime/smokeMainnetRead.js +529 -0
- package/dist/runtime/smokeMainnetReadAssertions.js +308 -0
- package/dist/runtime/start.js +295 -0
- package/dist/runtime/suiEndpoint.js +97 -0
- package/dist/runtime/suiTransactionGraphqlMapping.js +200 -0
- package/dist/runtime/suiTransactionGraphqlQueries.js +231 -0
- package/dist/runtime/suiTransactionGraphqlSource.js +148 -0
- package/docs/AGENT_BEHAVIOR.md +1 -1
- package/docs/AGENT_DEVELOPMENT_POLICY.md +20 -0
- package/docs/FRONTEND_POLICY.md +4 -3
- package/docs/MCP_SETUP.md +59 -7
- package/docs/MCP_TOOLS.md +1 -1
- package/docs/SDK_API.md +5 -1
- package/package.json +3 -2
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const EXTERNAL_PROPOSAL_CONTRACT_VERSION = "external-proposal-alpha-2026-05-25";
|
|
2
|
+
export const PROPOSAL_REVIEW_MODEL_VERSION = "proposal-review-model-alpha-2026-05-25";
|
|
3
|
+
export const EXTERNAL_PROPOSAL_SETTLEMENT_TOKEN_SELECTION_UNSUPPORTED_CLAIM_ID = "settlement_token_selection";
|
|
4
|
+
export const EXTERNAL_PROPOSAL_REVIEW_ALWAYS_UNSUPPORTED_CLAIMS = [
|
|
5
|
+
{
|
|
6
|
+
id: "external_transaction_material_trusted_authority",
|
|
7
|
+
label: "External transaction material",
|
|
8
|
+
reason: "External proposal data is not accepted as transaction-building input, signing data, or wallet authorization."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "signing_readiness",
|
|
12
|
+
label: "Signing readiness",
|
|
13
|
+
reason: "This review session is read-only and has no reviewed signable adapter, transaction regeneration, or wallet handoff."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "route_recommendation",
|
|
17
|
+
label: "Route recommendation",
|
|
18
|
+
reason: "The review model does not rank venues, choose routes, or make best-price recommendations."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: EXTERNAL_PROPOSAL_SETTLEMENT_TOKEN_SELECTION_UNSUPPORTED_CLAIM_ID,
|
|
22
|
+
label: "Settlement-token selection",
|
|
23
|
+
reason: "External proposal review can display declared asset fields, but it does not verify that the user selected a settlement token and does not choose one for the user."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "fiat_usd_cash_out",
|
|
27
|
+
label: "Fiat USD cash-out",
|
|
28
|
+
reason: "Settlement assets are not treated as fiat USD, bank cash-out amounts, or peg guarantees."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "profit_or_pnl",
|
|
32
|
+
label: "P&L, tax, and cost basis",
|
|
33
|
+
reason: "The current release does not compute profit, loss, tax, or cost basis."
|
|
34
|
+
}
|
|
35
|
+
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReadServiceInputError } from "./readServiceTypes.js";
|
|
2
|
+
export function sumRawAmounts(rawAmounts, field = "balance") {
|
|
3
|
+
let total = 0n;
|
|
4
|
+
for (const rawAmount of rawAmounts) {
|
|
5
|
+
if (!/^\d+$/.test(rawAmount)) {
|
|
6
|
+
throw new ReadServiceInputError("input_invalid", "raw amount must be an unsigned integer string", {
|
|
7
|
+
field,
|
|
8
|
+
value: rawAmount
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
total += BigInt(rawAmount);
|
|
12
|
+
}
|
|
13
|
+
return total.toString();
|
|
14
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { normalizeStructTag, parseToUnits } from "@mysten/sui/utils";
|
|
2
|
+
export const COIN_METADATA_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
export const SUI_METADATA_UNIT_SOURCE = "sui_core_getCoinMetadata";
|
|
4
|
+
export const DEEPBOOK_SCALAR_UNIT_SOURCE = "deepbook_mainnetCoins_scalar";
|
|
5
|
+
export const DISPLAY_AMOUNT_SOURCE = "raw_balance_with_verified_decimals";
|
|
6
|
+
export function normalizeCoinType(coinType) {
|
|
7
|
+
return normalizeStructTag(coinType);
|
|
8
|
+
}
|
|
9
|
+
export function decimalsFromScalar(scalar) {
|
|
10
|
+
if (!Number.isSafeInteger(scalar) || scalar < 1) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
let value = scalar;
|
|
14
|
+
let decimals = 0;
|
|
15
|
+
while (value > 1 && value % 10 === 0) {
|
|
16
|
+
value /= 10;
|
|
17
|
+
decimals += 1;
|
|
18
|
+
}
|
|
19
|
+
return value === 1 ? decimals : undefined;
|
|
20
|
+
}
|
|
21
|
+
export function assertValidDecimals(decimals) {
|
|
22
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 255) {
|
|
23
|
+
throw new Error("Coin metadata decimals must be an integer from 0 to 255");
|
|
24
|
+
}
|
|
25
|
+
return decimals;
|
|
26
|
+
}
|
|
27
|
+
export function formatRawAmount(rawAmount, decimals) {
|
|
28
|
+
assertValidDecimals(decimals);
|
|
29
|
+
if (!/^\d+$/.test(rawAmount)) {
|
|
30
|
+
throw new Error("raw amount must be an unsigned integer string");
|
|
31
|
+
}
|
|
32
|
+
const normalizedRaw = rawAmount.replace(/^0+(?=\d)/, "");
|
|
33
|
+
if (decimals === 0) {
|
|
34
|
+
return normalizedRaw;
|
|
35
|
+
}
|
|
36
|
+
const padded = normalizedRaw.padStart(decimals + 1, "0");
|
|
37
|
+
const integerPart = padded.slice(0, -decimals).replace(/^0+(?=\d)/, "");
|
|
38
|
+
const fractionalPart = padded.slice(-decimals).replace(/0+$/, "");
|
|
39
|
+
return fractionalPart.length === 0 ? integerPart : `${integerPart}.${fractionalPart}`;
|
|
40
|
+
}
|
|
41
|
+
export function assertDisplayAmountSyntax(displayAmount) {
|
|
42
|
+
if (!/^\d+(?:\.\d+)?$/.test(displayAmount)) {
|
|
43
|
+
throw new Error("display amount must be an unsigned decimal string");
|
|
44
|
+
}
|
|
45
|
+
return displayAmount;
|
|
46
|
+
}
|
|
47
|
+
export function parseDisplayAmountToRaw(displayAmount, decimals) {
|
|
48
|
+
assertValidDecimals(decimals);
|
|
49
|
+
assertDisplayAmountSyntax(displayAmount);
|
|
50
|
+
try {
|
|
51
|
+
return parseToUnits(displayAmount, decimals).toString();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
const message = error instanceof Error ? error.message : "unknown";
|
|
55
|
+
if (message.startsWith("Too many decimal places")) {
|
|
56
|
+
throw new Error("display amount has more fractional digits than verified decimals");
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
2
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
3
|
+
import { DeepBookClient } from "@mysten/deepbook-v3";
|
|
4
|
+
import { ReadServiceInputError } from "./readServiceTypes.js";
|
|
5
|
+
export function createDeepBookReadClient(input) {
|
|
6
|
+
const sdkClient = new DeepBookClient({
|
|
7
|
+
client: input.client,
|
|
8
|
+
address: input.simulationSender,
|
|
9
|
+
network: input.network,
|
|
10
|
+
...(input.balanceManagers === undefined ? {} : { balanceManagers: input.balanceManagers })
|
|
11
|
+
});
|
|
12
|
+
return {
|
|
13
|
+
midPrice: (poolKey) => sdkClient.midPrice(poolKey),
|
|
14
|
+
poolBookParams: (poolKey) => sdkClient.poolBookParams(poolKey),
|
|
15
|
+
getLevel2TicksFromMid: (poolKey, ticks) => sdkClient.getLevel2TicksFromMid(poolKey, ticks),
|
|
16
|
+
getQuoteQuantityOutRaw: (poolKey, baseQuantity) => simulateDeepbookRawQuote({
|
|
17
|
+
client: input.client,
|
|
18
|
+
simulationSender: input.simulationSender,
|
|
19
|
+
poolKey,
|
|
20
|
+
command: () => sdkClient.deepBook.getQuoteQuantityOut(poolKey, baseQuantity)
|
|
21
|
+
}),
|
|
22
|
+
getBaseQuantityOutRaw: (poolKey, quoteQuantity) => simulateDeepbookRawQuote({
|
|
23
|
+
client: input.client,
|
|
24
|
+
simulationSender: input.simulationSender,
|
|
25
|
+
poolKey,
|
|
26
|
+
command: () => sdkClient.deepBook.getBaseQuantityOut(poolKey, quoteQuantity)
|
|
27
|
+
}),
|
|
28
|
+
getQuoteQuantityOutInputFeeRaw: (poolKey, baseQuantity) => simulateDeepbookRawQuote({
|
|
29
|
+
client: input.client,
|
|
30
|
+
simulationSender: input.simulationSender,
|
|
31
|
+
poolKey,
|
|
32
|
+
command: () => sdkClient.deepBook.getQuoteQuantityOutInputFee(poolKey, baseQuantity)
|
|
33
|
+
}),
|
|
34
|
+
getBaseQuantityOutInputFeeRaw: (poolKey, quoteQuantity) => simulateDeepbookRawQuote({
|
|
35
|
+
client: input.client,
|
|
36
|
+
simulationSender: input.simulationSender,
|
|
37
|
+
poolKey,
|
|
38
|
+
command: () => sdkClient.deepBook.getBaseQuantityOutInputFee(poolKey, quoteQuantity)
|
|
39
|
+
}),
|
|
40
|
+
getBalanceManagerIds: (owner) => sdkClient.getBalanceManagerIds(owner),
|
|
41
|
+
accountExists: (poolKey, managerKey) => sdkClient.accountExists(poolKey, managerKey),
|
|
42
|
+
account: (poolKey, managerKey) => sdkClient.account(poolKey, managerKey),
|
|
43
|
+
lockedBalance: (poolKey, balanceManagerKey) => sdkClient.lockedBalance(poolKey, balanceManagerKey),
|
|
44
|
+
accountOpenOrders: (poolKey, managerKey) => sdkClient.accountOpenOrders(poolKey, managerKey)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function simulateDeepbookRawQuote(input) {
|
|
48
|
+
const tx = new Transaction();
|
|
49
|
+
tx.setSender(input.simulationSender);
|
|
50
|
+
tx.add(input.command());
|
|
51
|
+
const result = await input.client.core.simulateTransaction({
|
|
52
|
+
transaction: tx,
|
|
53
|
+
include: { commandResults: true, effects: true }
|
|
54
|
+
});
|
|
55
|
+
const returnValues = result.commandResults?.[0]?.returnValues;
|
|
56
|
+
if (!Array.isArray(returnValues) || returnValues.length < 3) {
|
|
57
|
+
throw new ReadServiceInputError("quote_unavailable", "DeepBook raw quote return values are unavailable", {
|
|
58
|
+
poolKey: input.poolKey,
|
|
59
|
+
expectedReturnValues: ["base_quantity_out", "quote_quantity_out", "deep_quantity_required"]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
baseOutRaw: parseU64ReturnValue(returnValues[0], "baseOutRaw", input.poolKey),
|
|
64
|
+
quoteOutRaw: parseU64ReturnValue(returnValues[1], "quoteOutRaw", input.poolKey),
|
|
65
|
+
deepRequiredRaw: parseU64ReturnValue(returnValues[2], "deepRequiredRaw", input.poolKey)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function parseU64ReturnValue(value, field, poolKey) {
|
|
69
|
+
const bcsValue = typeof value === "object" && value !== null && "bcs" in value ? value.bcs : undefined;
|
|
70
|
+
if (!(bcsValue instanceof Uint8Array)) {
|
|
71
|
+
throw new ReadServiceInputError("quote_unavailable", "DeepBook raw quote return value is unavailable", {
|
|
72
|
+
poolKey,
|
|
73
|
+
field
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return bcs.U64.parse(bcsValue).toString();
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new ReadServiceInputError("quote_unavailable", "DeepBook raw quote return value is not a u64", {
|
|
81
|
+
poolKey,
|
|
82
|
+
field,
|
|
83
|
+
reason: error instanceof Error ? error.message : "unknown"
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { formatRawAmount, parseDisplayAmountToRaw } from "./coinMetadata.js";
|
|
2
|
+
import { MAX_RAW_U64, parseRawU64 } from "../numeric/rawU64.js";
|
|
3
|
+
import { parseSuiAddress } from "../suiAddress.js";
|
|
4
|
+
import { DEEPBOOK_ACCOUNT_QUANTITY_KIND, DEEPBOOK_MID_PRICE_SEMANTICS_KIND, DEEPBOOK_QUOTE_QUANTITY_KIND, ReadServiceInputError } from "./readServiceTypes.js";
|
|
5
|
+
export const MAX_DEEPBOOK_QUOTE_RAW_AMOUNT = MAX_RAW_U64;
|
|
6
|
+
export function parseDeepbookRawU64(value, field, options = {}) {
|
|
7
|
+
return parseRawU64(value, field, options);
|
|
8
|
+
}
|
|
9
|
+
export function deepbookDisplayQuantitySemantics() {
|
|
10
|
+
return {
|
|
11
|
+
kind: DEEPBOOK_ACCOUNT_QUANTITY_KIND,
|
|
12
|
+
rawAmountAvailable: false,
|
|
13
|
+
notFor: ["signing", "funding", "route_liquidity", "withdrawal_readiness", "transaction_building"]
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function deepbookMidPriceSemantics() {
|
|
17
|
+
return {
|
|
18
|
+
kind: DEEPBOOK_MID_PRICE_SEMANTICS_KIND,
|
|
19
|
+
allowedUse: "deepbook_pool_mid_price_snapshot",
|
|
20
|
+
globalMarketPriceAvailable: false,
|
|
21
|
+
fiatUsdCashOutAvailable: false,
|
|
22
|
+
externalMarketPriceConversionAvailable: false,
|
|
23
|
+
externalMarketLookupAvailable: false,
|
|
24
|
+
usdPegAssumptionAvailable: false,
|
|
25
|
+
bankCashOutEstimateAvailable: false,
|
|
26
|
+
quoteComparisonAvailable: false,
|
|
27
|
+
priceImpactAvailable: false,
|
|
28
|
+
venueComparisonAvailable: false,
|
|
29
|
+
routeRecommendationAvailable: false,
|
|
30
|
+
profitAndLossAvailable: false,
|
|
31
|
+
costBasisAvailable: false,
|
|
32
|
+
notFor: [
|
|
33
|
+
"global_market_price",
|
|
34
|
+
"fiat_usd_cash_out",
|
|
35
|
+
"external_market_price_conversion",
|
|
36
|
+
"external_market_lookup",
|
|
37
|
+
"usd_peg_assumption",
|
|
38
|
+
"bank_cash_out_estimate",
|
|
39
|
+
"price_impact",
|
|
40
|
+
"mid_price_slippage",
|
|
41
|
+
"quote_vs_mid_slippage",
|
|
42
|
+
"effective_quote_price",
|
|
43
|
+
"venue_comparison",
|
|
44
|
+
"best_route",
|
|
45
|
+
"route_recommendation",
|
|
46
|
+
"transaction_building",
|
|
47
|
+
"signing_data",
|
|
48
|
+
"signing_readiness",
|
|
49
|
+
"profit_or_pnl",
|
|
50
|
+
"cost_basis"
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function deepbookQuoteQuantitySemantics(inputAmountKind) {
|
|
55
|
+
return {
|
|
56
|
+
kind: DEEPBOOK_QUOTE_QUANTITY_KIND,
|
|
57
|
+
inputAmountKind,
|
|
58
|
+
allowedUse: "indicative_deepbook_pool_quote",
|
|
59
|
+
rawAmountAvailable: true,
|
|
60
|
+
rawEvidenceField: "rawQuote",
|
|
61
|
+
paymentCoverageAvailable: false,
|
|
62
|
+
shortfallContributionAvailable: false,
|
|
63
|
+
routeDependentPaymentSupportAvailable: false,
|
|
64
|
+
requiresIntentEvidenceForCoverage: true,
|
|
65
|
+
canUseForPaymentAnswer: false,
|
|
66
|
+
canUseForShortfallAnswer: false,
|
|
67
|
+
doNotCombineWithPaymentAnswer: true,
|
|
68
|
+
requiredPaymentAnswerTool: "read.preview_intent_evidence",
|
|
69
|
+
paymentAnswerUseBlockedReason: "quote_output_is_price_reference_not_payment_answer",
|
|
70
|
+
requiredPaymentAnswerField: "responseSummary",
|
|
71
|
+
fiatUsdCashOutAvailable: false,
|
|
72
|
+
externalMarketPriceConversionAvailable: false,
|
|
73
|
+
externalMarketLookupAvailable: false,
|
|
74
|
+
usdPegAssumptionAvailable: false,
|
|
75
|
+
bankCashOutEstimateAvailable: false,
|
|
76
|
+
profitAndLossAvailable: false,
|
|
77
|
+
costBasisAvailable: false,
|
|
78
|
+
priceImpactAvailable: false,
|
|
79
|
+
midPriceSlippageAvailable: false,
|
|
80
|
+
venueComparisonAvailable: false,
|
|
81
|
+
routeRecommendationAvailable: false,
|
|
82
|
+
notFor: [
|
|
83
|
+
"signing",
|
|
84
|
+
"funding",
|
|
85
|
+
"payment_coverage",
|
|
86
|
+
"shortfall_contribution",
|
|
87
|
+
"route_dependent_payment_support",
|
|
88
|
+
"route_liquidity",
|
|
89
|
+
"min_out",
|
|
90
|
+
"liquidity_verdict",
|
|
91
|
+
"price_impact",
|
|
92
|
+
"mid_price_slippage",
|
|
93
|
+
"quote_vs_mid_slippage",
|
|
94
|
+
"effective_price",
|
|
95
|
+
"venue_comparison",
|
|
96
|
+
"best_route",
|
|
97
|
+
"route_recommendation",
|
|
98
|
+
"transaction_building",
|
|
99
|
+
"fiat_usd_cash_out",
|
|
100
|
+
"external_market_price_conversion",
|
|
101
|
+
"external_market_lookup",
|
|
102
|
+
"usd_peg_assumption",
|
|
103
|
+
"bank_cash_out_estimate",
|
|
104
|
+
"profit_or_pnl",
|
|
105
|
+
"cost_basis"
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function deepbookAccountInventorySource(methods) {
|
|
110
|
+
return {
|
|
111
|
+
sdk: "@mysten/deepbook-v3",
|
|
112
|
+
transport: "grpc",
|
|
113
|
+
simulation: "client.core.simulateTransaction",
|
|
114
|
+
methods
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function normalizeOptionalManagerAddress(value) {
|
|
118
|
+
if (value === undefined) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const normalized = parseSuiAddress(value);
|
|
122
|
+
if (normalized === undefined) {
|
|
123
|
+
throw new ReadServiceInputError("input_invalid", "managerAddress must be a valid Sui address", {
|
|
124
|
+
field: "managerAddress",
|
|
125
|
+
value
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return normalized;
|
|
129
|
+
}
|
|
130
|
+
export function normalizeManagerAddresses(values) {
|
|
131
|
+
return values.map((value) => {
|
|
132
|
+
const normalized = parseSuiAddress(value);
|
|
133
|
+
if (normalized === undefined) {
|
|
134
|
+
throw new Error("DeepBook BalanceManager ID was not a valid Sui address");
|
|
135
|
+
}
|
|
136
|
+
return normalized;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Account inventory v1 exposes only ledger and rebate balances; governance,
|
|
140
|
+
// stake, volume, and AccountInfo.open_orders need separate review before export.
|
|
141
|
+
export function toDeepbookAccountSummary(accountInfo) {
|
|
142
|
+
return {
|
|
143
|
+
epoch: accountInfo.epoch,
|
|
144
|
+
settledBalances: assertDeepbookDisplayBalances(accountInfo.settled_balances, "accountSummary.settledBalances"),
|
|
145
|
+
owedBalances: assertDeepbookDisplayBalances(accountInfo.owed_balances, "accountSummary.owedBalances"),
|
|
146
|
+
unclaimedRebates: assertDeepbookDisplayBalances(accountInfo.unclaimed_rebates, "accountSummary.unclaimedRebates")
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
export function assertDeepbookDisplayBalances(balances, field) {
|
|
150
|
+
assertDeepbookDisplayNumber(balances.base, `${field}.base`);
|
|
151
|
+
assertDeepbookDisplayNumber(balances.quote, `${field}.quote`);
|
|
152
|
+
assertDeepbookDisplayNumber(balances.deep, `${field}.deep`);
|
|
153
|
+
return balances;
|
|
154
|
+
}
|
|
155
|
+
export function parseQuoteDisplayAmount(displayAmount, decimals) {
|
|
156
|
+
let rawAmount;
|
|
157
|
+
try {
|
|
158
|
+
rawAmount = parseDisplayAmountToRaw(displayAmount, decimals);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
throw new ReadServiceInputError("input_invalid", "amountDisplay must be a positive unsigned decimal string within verified decimals", {
|
|
162
|
+
field: "amountDisplay",
|
|
163
|
+
value: displayAmount,
|
|
164
|
+
decimals,
|
|
165
|
+
reason: error instanceof Error ? error.message : "unknown"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (!/^[1-9]\d*$/.test(rawAmount)) {
|
|
169
|
+
throw new ReadServiceInputError("input_invalid", "amountDisplay must convert to a positive raw integer amount", {
|
|
170
|
+
field: "amountDisplay",
|
|
171
|
+
value: displayAmount,
|
|
172
|
+
decimals,
|
|
173
|
+
rawAmount
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
if (BigInt(rawAmount) > MAX_DEEPBOOK_QUOTE_RAW_AMOUNT) {
|
|
177
|
+
throw new ReadServiceInputError("input_invalid", "amountDisplay must convert to a raw integer amount that fits the DeepBook u64 quote input", {
|
|
178
|
+
field: "amountDisplay",
|
|
179
|
+
value: displayAmount,
|
|
180
|
+
decimals,
|
|
181
|
+
rawAmount,
|
|
182
|
+
maxRawAmount: MAX_DEEPBOOK_QUOTE_RAW_AMOUNT.toString()
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return rawAmount;
|
|
186
|
+
}
|
|
187
|
+
export function parseRawAmount(value) {
|
|
188
|
+
try {
|
|
189
|
+
return parseDeepbookRawU64(value, "amountRaw", { positive: true });
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
const reason = error instanceof Error ? error.message : "amountRaw is invalid";
|
|
193
|
+
if (reason === "amountRaw must fit u64") {
|
|
194
|
+
throw new ReadServiceInputError("input_invalid", "amountRaw must fit the DeepBook u64 quote input", {
|
|
195
|
+
field: "amountRaw",
|
|
196
|
+
value,
|
|
197
|
+
maxRawAmount: MAX_DEEPBOOK_QUOTE_RAW_AMOUNT.toString()
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
throw new ReadServiceInputError("input_invalid", "amountRaw must be a positive integer string", {
|
|
201
|
+
field: "amountRaw",
|
|
202
|
+
value
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
export function assertValidDeepbookMidPrice(poolKey, midPrice) {
|
|
207
|
+
if (!Number.isFinite(midPrice) || midPrice <= 0) {
|
|
208
|
+
throw new ReadServiceInputError("quote_unavailable", "DeepBook mid price is unavailable for this pool", {
|
|
209
|
+
poolKey,
|
|
210
|
+
source: "midPrice"
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return midPrice;
|
|
214
|
+
}
|
|
215
|
+
export function assertValidDeepbookQuote(poolKey, direction, quote) {
|
|
216
|
+
for (const [field, value] of Object.entries(quote)) {
|
|
217
|
+
if (typeof value !== "string" || !/^\d+(?:\.\d+)?$/.test(value)) {
|
|
218
|
+
throw new ReadServiceInputError("quote_unavailable", "DeepBook quote display amount is unavailable", {
|
|
219
|
+
poolKey,
|
|
220
|
+
direction,
|
|
221
|
+
field
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return quote;
|
|
226
|
+
}
|
|
227
|
+
export function toDeepbookDisplayQuoteFromRaw(quote, units) {
|
|
228
|
+
return {
|
|
229
|
+
baseOut: rawToDeepbookDisplayAmount(quote.baseOutRaw, units.baseDecimals),
|
|
230
|
+
quoteOut: rawToDeepbookDisplayAmount(quote.quoteOutRaw, units.quoteDecimals),
|
|
231
|
+
deepRequired: rawToDeepbookDisplayAmount(quote.deepRequiredRaw, units.deepDecimals)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
export function assertPositiveInteger(value, field, max) {
|
|
235
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
236
|
+
throw new ReadServiceInputError("input_invalid", `${field} must be a positive integer`, {
|
|
237
|
+
field,
|
|
238
|
+
value
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (max !== undefined && value > max) {
|
|
242
|
+
throw new ReadServiceInputError("input_invalid", `${field} must be less than or equal to ${max}`, {
|
|
243
|
+
field,
|
|
244
|
+
value,
|
|
245
|
+
max
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function assertDeepbookDisplayNumber(value, field) {
|
|
250
|
+
if (!Number.isFinite(value)) {
|
|
251
|
+
throw new Error(`DeepBook account inventory display number is unavailable for ${field}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function rawToDeepbookDisplayAmount(raw, decimals) {
|
|
255
|
+
try {
|
|
256
|
+
return formatRawAmount(raw, decimals);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
throw new ReadServiceInputError("quote_unavailable", "DeepBook raw quote return value cannot be displayed", {
|
|
260
|
+
raw,
|
|
261
|
+
decimals,
|
|
262
|
+
reason: error instanceof Error ? error.message : "unknown"
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { mainnetCoins, mainnetPools } from "@mysten/deepbook-v3";
|
|
2
|
+
import { DEEPBOOK_SCALAR_UNIT_SOURCE, decimalsFromScalar, normalizeCoinType } from "./coinMetadata.js";
|
|
3
|
+
import { ReadServiceInputError } from "./readServiceTypes.js";
|
|
4
|
+
export const PINNED_DEEPBOOK_COINS = mainnetCoins;
|
|
5
|
+
export function listDeepbookTokenRegistry(coins = PINNED_DEEPBOOK_COINS) {
|
|
6
|
+
assertDeepbookScalars(coins);
|
|
7
|
+
const poolKeysBySymbol = new Map();
|
|
8
|
+
for (const [poolKey, pool] of Object.entries(mainnetPools)) {
|
|
9
|
+
for (const symbol of [pool.baseCoin, pool.quoteCoin]) {
|
|
10
|
+
const current = poolKeysBySymbol.get(symbol) ?? [];
|
|
11
|
+
current.push(poolKey);
|
|
12
|
+
poolKeysBySymbol.set(symbol, current);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return Object.entries(coins)
|
|
16
|
+
.map(([symbol, coin]) => toDeepbookTokenRegistryEntry(symbol, coin, (poolKeysBySymbol.get(symbol) ?? []).sort()))
|
|
17
|
+
.sort((left, right) => left.symbol.localeCompare(right.symbol));
|
|
18
|
+
}
|
|
19
|
+
export function deepbookUnitForCoinType(coinType, coins) {
|
|
20
|
+
const entry = findDeepbookCoinEntry(coinType, coins);
|
|
21
|
+
if (!entry) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const decimals = decimalsFromScalar(entry.coin.scalar);
|
|
25
|
+
if (decimals === undefined) {
|
|
26
|
+
throw invalidDeepbookScalar(entry.symbol, entry.coin.scalar);
|
|
27
|
+
}
|
|
28
|
+
return { decimals, symbol: entry.symbol, name: entry.symbol };
|
|
29
|
+
}
|
|
30
|
+
export function findDeepbookCoinEntry(normalizedCoinType, coins) {
|
|
31
|
+
// Validate the whole pinned token unit registry before using any DeepBook
|
|
32
|
+
// coin match so one bad scalar cannot make the registry look partially trustworthy.
|
|
33
|
+
assertDeepbookScalars(coins);
|
|
34
|
+
for (const [symbol, coin] of Object.entries(coins)) {
|
|
35
|
+
if (normalizeCoinType(coin.type) === normalizedCoinType) {
|
|
36
|
+
return { symbol, coin };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
export function getDeepbookCoinEntryBySymbol(symbol, coins) {
|
|
42
|
+
assertDeepbookScalars(coins);
|
|
43
|
+
const coin = coins[symbol];
|
|
44
|
+
if (!coin) {
|
|
45
|
+
throw new ReadServiceInputError("registry_miss", "DeepBook pool coin is missing from the pinned token registry", {
|
|
46
|
+
symbol
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return { symbol, coin };
|
|
50
|
+
}
|
|
51
|
+
export function canonicalDeepbookSymbol(symbol, coins = PINNED_DEEPBOOK_COINS) {
|
|
52
|
+
const trimmed = symbol.trim();
|
|
53
|
+
if (!trimmed) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const matches = Object.keys(coins).filter((candidate) => candidate.toLowerCase() === trimmed.toLowerCase());
|
|
57
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
58
|
+
}
|
|
59
|
+
export function getKnownPool(poolKey) {
|
|
60
|
+
const pool = mainnetPools[poolKey];
|
|
61
|
+
if (!pool) {
|
|
62
|
+
throw new ReadServiceInputError("registry_miss", "Unknown DeepBook mainnet pool key", { poolKey });
|
|
63
|
+
}
|
|
64
|
+
return pool;
|
|
65
|
+
}
|
|
66
|
+
export function resolveDeepbookPoolForSymbols(input) {
|
|
67
|
+
const matches = [];
|
|
68
|
+
for (const [poolKey, pool] of Object.entries(mainnetPools)) {
|
|
69
|
+
if (pool.baseCoin === input.sourceSymbol && pool.quoteCoin === input.targetSymbol) {
|
|
70
|
+
matches.push({
|
|
71
|
+
poolKey,
|
|
72
|
+
pool,
|
|
73
|
+
direction: "base_to_quote",
|
|
74
|
+
sourceSymbol: input.sourceSymbol,
|
|
75
|
+
targetSymbol: input.targetSymbol
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (pool.quoteCoin === input.sourceSymbol && pool.baseCoin === input.targetSymbol) {
|
|
79
|
+
matches.push({
|
|
80
|
+
poolKey,
|
|
81
|
+
pool,
|
|
82
|
+
direction: "quote_to_base",
|
|
83
|
+
sourceSymbol: input.sourceSymbol,
|
|
84
|
+
targetSymbol: input.targetSymbol
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (matches.length === 1) {
|
|
89
|
+
return matches[0];
|
|
90
|
+
}
|
|
91
|
+
if (matches.length > 1) {
|
|
92
|
+
throw new ReadServiceInputError("registry_miss", "DeepBook symbol pair resolves to multiple mainnet pools", {
|
|
93
|
+
sourceSymbol: input.sourceSymbol,
|
|
94
|
+
targetSymbol: input.targetSymbol,
|
|
95
|
+
poolKeys: matches.map((match) => match.poolKey)
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
throw new ReadServiceInputError("registry_miss", "DeepBook symbol pair is not a known direct mainnet pool", {
|
|
99
|
+
sourceSymbol: input.sourceSymbol,
|
|
100
|
+
targetSymbol: input.targetSymbol
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function invalidDeepbookScalar(symbol, scalar) {
|
|
104
|
+
return new ReadServiceInputError("registry_miss", "DeepBook token scalar is not a power of ten", {
|
|
105
|
+
symbol,
|
|
106
|
+
scalar
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function toDeepbookTokenRegistryEntry(symbol, coin, poolKeys) {
|
|
110
|
+
const decimals = decimalsFromScalar(coin.scalar);
|
|
111
|
+
if (decimals === undefined) {
|
|
112
|
+
throw invalidDeepbookScalar(symbol, coin.scalar);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
symbol,
|
|
116
|
+
address: coin.address,
|
|
117
|
+
type: coin.type,
|
|
118
|
+
scalar: coin.scalar,
|
|
119
|
+
decimals,
|
|
120
|
+
unitSource: DEEPBOOK_SCALAR_UNIT_SOURCE,
|
|
121
|
+
...(coin.feed === undefined ? {} : { feed: coin.feed }),
|
|
122
|
+
...(coin.currencyId === undefined ? {} : { currencyId: coin.currencyId }),
|
|
123
|
+
...(coin.priceInfoObjectId === undefined ? {} : { priceInfoObjectId: coin.priceInfoObjectId }),
|
|
124
|
+
poolKeys
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function assertDeepbookScalars(coins) {
|
|
128
|
+
for (const [symbol, coin] of Object.entries(coins)) {
|
|
129
|
+
if (decimalsFromScalar(coin.scalar) === undefined) {
|
|
130
|
+
throw invalidDeepbookScalar(symbol, coin.scalar);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|