@v3finance/core-sdk 0.2.1 → 0.2.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/CHANGELOG.md +30 -0
- package/README.md +2 -1
- package/dist/cjs/generated/operations.js +1 -1
- package/dist/cjs/generated/types.d.ts +13 -7
- package/dist/cjs/generated/types.d.ts.map +1 -1
- package/dist/cjs/resources/approvals.d.ts +22 -0
- package/dist/cjs/resources/approvals.d.ts.map +1 -1
- package/dist/cjs/resources/approvals.js +22 -0
- package/dist/cjs/resources/approvals.js.map +1 -1
- package/dist/cjs/resources/transfers.d.ts +64 -16
- package/dist/cjs/resources/transfers.d.ts.map +1 -1
- package/dist/cjs/resources/transfers.js +64 -16
- package/dist/cjs/resources/transfers.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/generated/operations.js +1 -1
- package/dist/esm/generated/types.d.ts +13 -7
- package/dist/esm/generated/types.d.ts.map +1 -1
- package/dist/esm/resources/approvals.d.ts +22 -0
- package/dist/esm/resources/approvals.d.ts.map +1 -1
- package/dist/esm/resources/approvals.js +22 -0
- package/dist/esm/resources/approvals.js.map +1 -1
- package/dist/esm/resources/transfers.d.ts +64 -16
- package/dist/esm/resources/transfers.d.ts.map +1 -1
- package/dist/esm/resources/transfers.js +64 -16
- package/dist/esm/resources/transfers.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/concepts.md +2 -1
- package/docs/errors.md +30 -12
- package/package.json +1 -1
- package/src/generated/operations.ts +1 -1
- package/src/generated/types.ts +13 -7
- package/src/resources/approvals.ts +22 -0
- package/src/resources/transfers.ts +64 -16
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,36 @@
|
|
|
3
3
|
All notable changes to this package are documented in this file. The format is based on
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
|
|
5
5
|
|
|
6
|
+
## 0.2.2 — 2026-11-12
|
|
7
|
+
|
|
8
|
+
Spec snapshot refreshed from the live API (commit `3ca1538`,
|
|
9
|
+
[v3-finance/policy-engine#22](https://github.com/v3-finance/policy-engine/pull/22)). No operation
|
|
10
|
+
was added or removed, and no code in this package changed: the API's money path did.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `transfers.send()` — when the signing service gives no definite answer, the transfer is no
|
|
15
|
+
longer failed: it stays `pending` with its funds reserved, the call throws 502
|
|
16
|
+
`TRANSFER_OUTCOME_UNKNOWN` (`details.transactionId`), and an administrator's reconciliation
|
|
17
|
+
settles it. Retry only with the same `idempotencyKey`. `WALLET_SERVICE_ERROR` on a transfer is
|
|
18
|
+
now only the 400 of a definite refusal; the documented 502 "retry with a new key" is gone.
|
|
19
|
+
- `transfers.send()` — the same key with different parameters is 409 `IDEMPOTENCY_KEY_REUSED`, not
|
|
20
|
+
the earlier transfer; `toAddress` is checked against the network before anything is reserved,
|
|
21
|
+
400 `INVALID_DESTINATION_ADDRESS`.
|
|
22
|
+
- `transfers.vote()` and `approvals.vote()` — an unknown outcome is not an error: `pending` with
|
|
23
|
+
`executionError: null`, or `APPROVED` with `finalized: false` and `applyError: null`. That answer
|
|
24
|
+
does not establish the outcome; read the transfer. Repeating the same vote on an open request
|
|
25
|
+
finishes it instead of answering 409 `ALREADY_VOTED`.
|
|
26
|
+
- `transfers.reconcile()` — `ReconcileTransferResult.status` gains `rejected` and `cancelled`
|
|
27
|
+
(a closed transfer whose reserve is still held: the reserve is returned, the status stays). An
|
|
28
|
+
exhaustiveness check over `confirmed | failed` stops compiling. A `pending` transfer that holds a
|
|
29
|
+
hash from the signing service is settled only by that hash, sent explicitly.
|
|
30
|
+
- `failureReason` is `null` on every status except `failed`, `rejected` and `cancelled`.
|
|
31
|
+
- `docs/errors.md`: the new codes — `TRANSFER_OUTCOME_UNKNOWN`, `TRANSFER_BROADCAST_UNRECORDED`,
|
|
32
|
+
`IDEMPOTENCY_KEY_REUSED`, `INVALID_DESTINATION_ADDRESS`, `REQUEST_INCOMPLETE`, and for
|
|
33
|
+
reconciliation `TRANSFER_BROADCAST`, `TXHASH_MISMATCH`, `TXHASH_IN_USE`, `TRANSFER_NOT_EXECUTED`,
|
|
34
|
+
`RESERVE_MISSING`, `RESERVE_RELEASED`.
|
|
35
|
+
|
|
6
36
|
## 0.2.1 — 2026-11-12
|
|
7
37
|
|
|
8
38
|
### Added
|
package/README.md
CHANGED
|
@@ -127,7 +127,8 @@ switch (result.outcome) {
|
|
|
127
127
|
Reporting "sent" on `pending` tells a person their money has gone when it is frozen. `replayed` is
|
|
128
128
|
not "sent" either: it means a transfer with this key already existed, and its `status` says whether
|
|
129
129
|
it went out (`confirmed` or `submitted`), is waiting for signatures (`awaiting_approval`), is still
|
|
130
|
-
executing (`pending`) or did not go out (`failed`,
|
|
130
|
+
executing or waiting for an administrator to reconcile it (`pending`) or did not go out (`failed`,
|
|
131
|
+
`rejected`, `cancelled`).
|
|
131
132
|
|
|
132
133
|
**Always pass `idempotencyKey`** on a transfer and keep it until you have an answer: after a
|
|
133
134
|
timeout it is the only way to retry without sending money twice. The key is read from the request
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// the API does not slip in unclassified.
|
|
11
11
|
//
|
|
12
12
|
// Operations: 171 · admin: 40 · both: 1 · member: 127 · service: 3
|
|
13
|
-
// Spec sha256:
|
|
13
|
+
// Spec sha256: 30be5f9b9733d1d1d67eebf21e0bfaa457651e951676211ec9fa464cca5d3795
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.OPERATIONS = void 0;
|
|
16
16
|
exports.isAdminOperation = isAdminOperation;
|
|
@@ -297,6 +297,7 @@ export interface OutgoingTxSummary {
|
|
|
297
297
|
status: string;
|
|
298
298
|
txHash: string | null;
|
|
299
299
|
fee: string | null;
|
|
300
|
+
/** Причина закрытия — только у failed/rejected/cancelled. У остальных статусов (awaiting_approval, pending, submitted, confirmed) — ВСЕГДА null: у незакрытого перевода причины отказа нет. Неясный исход исполнения (pending, транзакция могла уйти в сеть) здесь не показывается — его признак pending дольше 10 минут по updatedAt («ждёт сверки администратором») */
|
|
300
301
|
failureReason: string | null;
|
|
301
302
|
/** format: date-time */
|
|
302
303
|
createdAt: string;
|
|
@@ -1625,7 +1626,7 @@ export interface CreateTransactionResult {
|
|
|
1625
1626
|
amountDecimal: string;
|
|
1626
1627
|
asset: string;
|
|
1627
1628
|
network: string;
|
|
1628
|
-
/**
|
|
1629
|
+
/** 201 — confirmed (исполнен сейчас); редко pending с заполненным txHash (транзакция ушла в сеть, а учёт не записался — доводит сверка, повторять перевод нельзя); 202 — awaiting_approval; 200 (replay по idempotencyKey) — ТЕКУЩИЙ статус перевода, любой: pending (первый запрос ещё исполняется — или его исход неизвестен: первый ответ был 502 TRANSFER_OUTCOME_UNKNOWN; повтор НЕ исполняет перевод заново, исход устанавливает сверка), awaiting_approval, confirmed, failed, rejected, cancelled */
|
|
1629
1630
|
status: string;
|
|
1630
1631
|
txHash: string | null;
|
|
1631
1632
|
fee: string | null;
|
|
@@ -1639,12 +1640,13 @@ export interface CreateTransactionResult {
|
|
|
1639
1640
|
}
|
|
1640
1641
|
export interface CreateTransferBody {
|
|
1641
1642
|
fromAddressId: string;
|
|
1643
|
+
/** Адрес получателя. Формат проверяется по типу сети адреса-отправителя ДО резерва средств: TRON — base58check (34 символа, «T…», контрольная сумма), EVM — 0x + 40 hex (смешанный регистр — контрольная сумма EIP-55). Не подошёл — 400 INVALID_DESTINATION_ADDRESS. Строка проверяется как есть, пробелы по краям — ошибка формата */
|
|
1642
1644
|
toAddress: string;
|
|
1643
1645
|
/** DECIMAL строка — конвертируется по token.decimals */
|
|
1644
1646
|
amount: string;
|
|
1645
1647
|
asset: string;
|
|
1646
1648
|
/**
|
|
1647
|
-
* Уникальный ключ попытки перевода (рекомендуется: uuid). Повторный запрос с тем же ключом вернёт
|
|
1649
|
+
* Уникальный ключ попытки перевода (рекомендуется: uuid). Повторный запрос с тем же ключом и теми же параметрами вернёт 200 с существующим переводом — без второго broadcast, без повторной оценки политик. Тот же ключ с другими параметрами — 409 IDEMPOTENCY_KEY_REUSED. Для новой попытки после failed — новый ключ.
|
|
1648
1650
|
*
|
|
1649
1651
|
* length: 8..128
|
|
1650
1652
|
*/
|
|
@@ -1915,6 +1917,7 @@ export interface HistoryOutItem {
|
|
|
1915
1917
|
asset: string;
|
|
1916
1918
|
assetSymbol: string;
|
|
1917
1919
|
fee: string | null;
|
|
1920
|
+
/** Причина закрытия — только у failed/rejected/cancelled. У остальных статусов (awaiting_approval, pending, submitted, confirmed) — ВСЕГДА null: у незакрытого перевода причины отказа нет. Неясный исход исполнения (pending, транзакция могла уйти в сеть) здесь не показывается — его признак pending дольше 10 минут по updatedAt («ждёт сверки администратором») */
|
|
1918
1921
|
failureReason: string | null;
|
|
1919
1922
|
fromAddress: {
|
|
1920
1923
|
id: string;
|
|
@@ -2991,7 +2994,7 @@ export interface RatesResponse {
|
|
|
2991
2994
|
}>;
|
|
2992
2995
|
}
|
|
2993
2996
|
export interface ReconcileTransferBody {
|
|
2994
|
-
/** Хеш от подписывающего сервиса. ЕСТЬ — транзакция ушла в сеть, перевод доводится до confirmed. НЕТ (или null) —
|
|
2997
|
+
/** Хеш от подписывающего сервиса. ЕСТЬ — транзакция ушла в сеть, перевод доводится до confirmed. НЕТ (или null) — сверяющий утверждает, что broadcast'а не было, и резерв возвращается (failed). Для pending с неясным исходом (у pending без txHash его не отличить по ответам API — failureReason у незакрытого перевода null) это утверждение нужно ПРОВЕРИТЬ по сети: возврат за ушедшую транзакцию печатает деньги. Если у pending-перевода хеш уже сохранён (broadcast прошёл), он обязателен: без него — 409 TRANSFER_BROADCAST, с другим — 409 TXHASH_MISMATCH (сохранённый — в error.details.txHash) */
|
|
2995
2998
|
txHash?: string | null;
|
|
2996
2999
|
/** Комиссия, если известна */
|
|
2997
3000
|
fee?: string | null;
|
|
@@ -2999,7 +3002,8 @@ export interface ReconcileTransferBody {
|
|
|
2999
3002
|
reason?: string | null;
|
|
3000
3003
|
}
|
|
3001
3004
|
export interface ReconcileTransferResult {
|
|
3002
|
-
|
|
3005
|
+
/** Статус перевода после сверки: confirmed (по хешу) | failed (резерв возвращён). rejected/cancelled — у закрытого перевода с невозвращённым резервом: резерв возвращён, статус прежний */
|
|
3006
|
+
status: "confirmed" | "failed" | "rejected" | "cancelled";
|
|
3003
3007
|
txHash: string | null;
|
|
3004
3008
|
}
|
|
3005
3009
|
export interface RegisterPushTokenBody {
|
|
@@ -3018,8 +3022,9 @@ export interface RequestVoteResult {
|
|
|
3018
3022
|
approvals: number;
|
|
3019
3023
|
/** range: -9007199254740991..9007199254740991 */
|
|
3020
3024
|
threshold: number;
|
|
3021
|
-
/** true — этот голос финализировал заявку (применена/отклонена) */
|
|
3025
|
+
/** true — этот голос финализировал заявку (применена/отклонена). У заявки на перевод status=APPROVED при finalized=false значит, что исход рассчитал НЕ этот вызов: applyError пуст — перевод исполняет (исполнил) параллельный запрос ЛИБО исполнение, начатое другим вызовом, оборвалось (сам перевод тогда не закроется); исход — только по GET /transfers/{id}: confirmed/failed, а pending дольше 10 минут по updatedAt — ждёт сверки (admin). applyError TRANSFER_EXECUTION_FAILED — к моменту одобрения перевод уже не ждал подписей. finalized=false с пустым applyError приходит и тогда, когда одобрил ЭТОТ голос, но исход перевода им не установлен (перевод pending: подписывающий сервис не дал определённого ответа, транзакция могла уйти в сеть, а могла и нет): показывайте «голос учтён», не «применено». finalized=true с пустым applyError у перевода — исполнен этим вызовом (confirmed) */
|
|
3022
3026
|
finalized: boolean;
|
|
3027
|
+
/** Голос финализировал заявку, а применение не дало результата; status при этом итоговый. Коды: STALE — цель изменилась (status=REJECTED); APPLY_FAILED / APPLY_FAILED_ROLLED_BACK / APPLY_FAILED_PARTIAL — мутация не применена (целиком / цепочка откатана / частично). У action=transfer финальный approve ИСПОЛНЯЕТ перевод, status=APPROVED: TRANSFER_EXECUTION_FAILED — перевод не исполнен (обычно failed, резерв возвращён; точный статус — GET /transfers/{id}; при finalized=false — перевод уже не ждал подписей, одобрение его не исполняло). Неясный исход перевода (подписывающий сервис не дал определённого ответа, перевод pending, средства зарезервированы, транзакция могла уйти в сеть, исход установит сверка, admin) ошибкой НЕ отдаётся: applyError null, status APPROVED, finalized=false. Кода TRANSFER_OUTCOME_UNKNOWN здесь нет — он только у POST /transfers */
|
|
3023
3028
|
applyError: {
|
|
3024
3029
|
code: string;
|
|
3025
3030
|
message: string;
|
|
@@ -3179,6 +3184,7 @@ export interface TransactionDetail {
|
|
|
3179
3184
|
decisionPolicyCode: string | null;
|
|
3180
3185
|
/** Человеческое название решающей политики (для UI вместо кода) */
|
|
3181
3186
|
decisionPolicyName: string | null;
|
|
3187
|
+
/** Причина закрытия — только у failed/rejected/cancelled. У остальных статусов (awaiting_approval, pending, submitted, confirmed) — ВСЕГДА null: у незакрытого перевода причины отказа нет. Неясный исход исполнения (pending, транзакция могла уйти в сеть) здесь не показывается — его признак pending дольше 10 минут по updatedAt («ждёт сверки администратором») */
|
|
3182
3188
|
failureReason: string | null;
|
|
3183
3189
|
/** format: date-time */
|
|
3184
3190
|
createdAt: string;
|
|
@@ -3496,7 +3502,7 @@ export interface VoteRequestBody {
|
|
|
3496
3502
|
comment?: string;
|
|
3497
3503
|
}
|
|
3498
3504
|
export interface VoteResult {
|
|
3499
|
-
/** Статус перевода ПОСЛЕ голоса: awaiting_approval (голосов мало) | rejected | confirmed/failed (финальный approve исполняет сразу) */
|
|
3505
|
+
/** Статус перевода ПОСЛЕ голоса: awaiting_approval (голосов мало) | rejected | confirmed/failed (финальный approve исполняет сразу). pending — исполнение не закончено, повторять перевод нельзя; executionError у pending всегда null, исход этим ответом НЕ установлен, ждать его «через секунды» нельзя. Так отдаётся и неясный исход (подписывающий сервис не дал определённого ответа, транзакция могла уйти в сеть, резерв стоит — доводит сверка, admin), и: txHash в GET /transfers/{id} есть — транзакция ушла в сеть, а учёт не записался, доводит сверка (admin) по этому хешу; перевод исполняет параллельный запрос (одновременный голос другого подписанта или исходный вызов при повторе голоса) ЛИБО исполнение оборвалось (клиент, который его начал, отключился — сам перевод тогда не закроется). Различает только время: перечитывайте GET; confirmed/failed — исход; pending дольше 10 минут по updatedAt — «ждёт сверки администратором» */
|
|
3500
3506
|
status: string;
|
|
3501
3507
|
/**
|
|
3502
3508
|
* Собрано approve-голосов
|
|
@@ -3506,7 +3512,7 @@ export interface VoteResult {
|
|
|
3506
3512
|
approvals: number;
|
|
3507
3513
|
/** range: -9007199254740991..9007199254740991 */
|
|
3508
3514
|
threshold: number;
|
|
3509
|
-
/**
|
|
3515
|
+
/** Финальный approve запустил исполнение, и оно перевод НЕ исполнило. code: TRANSFER_EXECUTION_FAILED — не исполнен (status=failed, средства возвращены; исключения: failed с txHash у перевода, см. описание ручки, и status=pending, если сам возврат резерва не записался — тогда перевод доводит сверка). Тот же код — если к моменту одобрения перевод уже не ждал подписей (status — его фактический: failed/rejected/cancelled): одобрение его не исполнило. Неясный исход (подписывающий сервис не дал определённого ответа, транзакция могла уйти в сеть) ошибкой НЕ отдаётся: status=pending, executionError=null — показывайте «исполняется, исход уточняется». Кода TRANSFER_OUTCOME_UNKNOWN в голосе нет, он только у POST /transfers */
|
|
3510
3516
|
executionError: {
|
|
3511
3517
|
code: string;
|
|
3512
3518
|
message: string;
|