@v3finance/core-sdk 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +441 -7
- package/README.md +219 -73
- package/dist/cjs/client.d.ts +67 -22
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +38 -2
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/core/errors.d.ts +30 -10
- package/dist/cjs/core/errors.d.ts.map +1 -1
- package/dist/cjs/core/errors.js +47 -15
- package/dist/cjs/core/errors.js.map +1 -1
- package/dist/cjs/core/gated.d.ts +30 -6
- package/dist/cjs/core/gated.d.ts.map +1 -1
- package/dist/cjs/core/gated.js +21 -6
- package/dist/cjs/core/gated.js.map +1 -1
- package/dist/cjs/core/http.d.ts +12 -8
- package/dist/cjs/core/http.d.ts.map +1 -1
- package/dist/cjs/core/http.js +147 -43
- package/dist/cjs/core/http.js.map +1 -1
- package/dist/cjs/core/pagination.d.ts +28 -1
- package/dist/cjs/core/pagination.d.ts.map +1 -1
- package/dist/cjs/core/pagination.js +36 -1
- package/dist/cjs/core/pagination.js.map +1 -1
- package/dist/cjs/generated/operations.js +1 -1
- package/dist/cjs/generated/types.d.ts +965 -179
- package/dist/cjs/generated/types.d.ts.map +1 -1
- package/dist/cjs/index.d.ts +32 -8
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/resources/addresses.d.ts +23 -8
- package/dist/cjs/resources/addresses.d.ts.map +1 -1
- package/dist/cjs/resources/addresses.js +8 -1
- package/dist/cjs/resources/addresses.js.map +1 -1
- package/dist/cjs/resources/admin.d.ts +150 -25
- package/dist/cjs/resources/admin.d.ts.map +1 -1
- package/dist/cjs/resources/admin.js +94 -23
- package/dist/cjs/resources/admin.js.map +1 -1
- package/dist/cjs/resources/approvals.d.ts +46 -5
- package/dist/cjs/resources/approvals.d.ts.map +1 -1
- package/dist/cjs/resources/approvals.js +27 -4
- package/dist/cjs/resources/approvals.js.map +1 -1
- package/dist/cjs/resources/balances.d.ts +152 -16
- package/dist/cjs/resources/balances.d.ts.map +1 -1
- package/dist/cjs/resources/balances.js +9 -5
- package/dist/cjs/resources/balances.js.map +1 -1
- package/dist/cjs/resources/categories.d.ts +93 -21
- package/dist/cjs/resources/categories.d.ts.map +1 -1
- package/dist/cjs/resources/categories.js +65 -18
- package/dist/cjs/resources/categories.js.map +1 -1
- package/dist/cjs/resources/counterparties.d.ts +26 -3
- package/dist/cjs/resources/counterparties.d.ts.map +1 -1
- package/dist/cjs/resources/counterparties.js +17 -0
- package/dist/cjs/resources/counterparties.js.map +1 -1
- package/dist/cjs/resources/folders.d.ts +51 -10
- package/dist/cjs/resources/folders.d.ts.map +1 -1
- package/dist/cjs/resources/folders.js +36 -5
- package/dist/cjs/resources/folders.js.map +1 -1
- package/dist/cjs/resources/history.d.ts +20 -2
- package/dist/cjs/resources/history.d.ts.map +1 -1
- package/dist/cjs/resources/history.js.map +1 -1
- package/dist/cjs/resources/me.d.ts +27 -4
- package/dist/cjs/resources/me.d.ts.map +1 -1
- package/dist/cjs/resources/me.js +22 -1
- package/dist/cjs/resources/me.js.map +1 -1
- package/dist/cjs/resources/members.d.ts +19 -4
- package/dist/cjs/resources/members.d.ts.map +1 -1
- package/dist/cjs/resources/members.js +15 -6
- package/dist/cjs/resources/members.js.map +1 -1
- package/dist/cjs/resources/operations.d.ts +64 -8
- package/dist/cjs/resources/operations.d.ts.map +1 -1
- package/dist/cjs/resources/operations.js +26 -2
- package/dist/cjs/resources/operations.js.map +1 -1
- package/dist/cjs/resources/registries.d.ts +87 -9
- package/dist/cjs/resources/registries.d.ts.map +1 -1
- package/dist/cjs/resources/registries.js +54 -11
- package/dist/cjs/resources/registries.js.map +1 -1
- package/dist/cjs/resources/reports.d.ts +300 -41
- package/dist/cjs/resources/reports.d.ts.map +1 -1
- package/dist/cjs/resources/reports.js +135 -7
- package/dist/cjs/resources/reports.js.map +1 -1
- package/dist/cjs/resources/sharing.d.ts +61 -10
- package/dist/cjs/resources/sharing.d.ts.map +1 -1
- package/dist/cjs/resources/sharing.js +51 -4
- package/dist/cjs/resources/sharing.js.map +1 -1
- package/dist/cjs/resources/transfers.d.ts +44 -6
- package/dist/cjs/resources/transfers.d.ts.map +1 -1
- package/dist/cjs/resources/transfers.js +41 -3
- package/dist/cjs/resources/transfers.js.map +1 -1
- package/dist/cjs/resources/types.d.ts +16 -0
- package/dist/cjs/resources/types.d.ts.map +1 -1
- package/dist/cjs/units.d.ts.map +1 -1
- package/dist/cjs/units.js +18 -2
- package/dist/cjs/units.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client.d.ts +67 -22
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +38 -2
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/core/errors.d.ts +30 -10
- package/dist/esm/core/errors.d.ts.map +1 -1
- package/dist/esm/core/errors.js +47 -15
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/gated.d.ts +30 -6
- package/dist/esm/core/gated.d.ts.map +1 -1
- package/dist/esm/core/gated.js +21 -6
- package/dist/esm/core/gated.js.map +1 -1
- package/dist/esm/core/http.d.ts +12 -8
- package/dist/esm/core/http.d.ts.map +1 -1
- package/dist/esm/core/http.js +148 -44
- package/dist/esm/core/http.js.map +1 -1
- package/dist/esm/core/pagination.d.ts +28 -1
- package/dist/esm/core/pagination.d.ts.map +1 -1
- package/dist/esm/core/pagination.js +36 -1
- package/dist/esm/core/pagination.js.map +1 -1
- package/dist/esm/generated/operations.js +1 -1
- package/dist/esm/generated/types.d.ts +965 -179
- package/dist/esm/generated/types.d.ts.map +1 -1
- package/dist/esm/index.d.ts +32 -8
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +17 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resources/addresses.d.ts +23 -8
- package/dist/esm/resources/addresses.d.ts.map +1 -1
- package/dist/esm/resources/addresses.js +8 -1
- package/dist/esm/resources/addresses.js.map +1 -1
- package/dist/esm/resources/admin.d.ts +150 -25
- package/dist/esm/resources/admin.d.ts.map +1 -1
- package/dist/esm/resources/admin.js +94 -23
- package/dist/esm/resources/admin.js.map +1 -1
- package/dist/esm/resources/approvals.d.ts +46 -5
- package/dist/esm/resources/approvals.d.ts.map +1 -1
- package/dist/esm/resources/approvals.js +27 -4
- package/dist/esm/resources/approvals.js.map +1 -1
- package/dist/esm/resources/balances.d.ts +152 -16
- package/dist/esm/resources/balances.d.ts.map +1 -1
- package/dist/esm/resources/balances.js +9 -5
- package/dist/esm/resources/balances.js.map +1 -1
- package/dist/esm/resources/categories.d.ts +93 -21
- package/dist/esm/resources/categories.d.ts.map +1 -1
- package/dist/esm/resources/categories.js +65 -18
- package/dist/esm/resources/categories.js.map +1 -1
- package/dist/esm/resources/counterparties.d.ts +26 -3
- package/dist/esm/resources/counterparties.d.ts.map +1 -1
- package/dist/esm/resources/counterparties.js +17 -0
- package/dist/esm/resources/counterparties.js.map +1 -1
- package/dist/esm/resources/folders.d.ts +51 -10
- package/dist/esm/resources/folders.d.ts.map +1 -1
- package/dist/esm/resources/folders.js +36 -5
- package/dist/esm/resources/folders.js.map +1 -1
- package/dist/esm/resources/history.d.ts +20 -2
- package/dist/esm/resources/history.d.ts.map +1 -1
- package/dist/esm/resources/history.js.map +1 -1
- package/dist/esm/resources/me.d.ts +27 -4
- package/dist/esm/resources/me.d.ts.map +1 -1
- package/dist/esm/resources/me.js +22 -1
- package/dist/esm/resources/me.js.map +1 -1
- package/dist/esm/resources/members.d.ts +19 -4
- package/dist/esm/resources/members.d.ts.map +1 -1
- package/dist/esm/resources/members.js +15 -6
- package/dist/esm/resources/members.js.map +1 -1
- package/dist/esm/resources/operations.d.ts +64 -8
- package/dist/esm/resources/operations.d.ts.map +1 -1
- package/dist/esm/resources/operations.js +26 -2
- package/dist/esm/resources/operations.js.map +1 -1
- package/dist/esm/resources/registries.d.ts +87 -9
- package/dist/esm/resources/registries.d.ts.map +1 -1
- package/dist/esm/resources/registries.js +54 -11
- package/dist/esm/resources/registries.js.map +1 -1
- package/dist/esm/resources/reports.d.ts +300 -41
- package/dist/esm/resources/reports.d.ts.map +1 -1
- package/dist/esm/resources/reports.js +135 -7
- package/dist/esm/resources/reports.js.map +1 -1
- package/dist/esm/resources/sharing.d.ts +61 -10
- package/dist/esm/resources/sharing.d.ts.map +1 -1
- package/dist/esm/resources/sharing.js +51 -4
- package/dist/esm/resources/sharing.js.map +1 -1
- package/dist/esm/resources/transfers.d.ts +44 -6
- package/dist/esm/resources/transfers.d.ts.map +1 -1
- package/dist/esm/resources/transfers.js +41 -3
- package/dist/esm/resources/transfers.js.map +1 -1
- package/dist/esm/resources/types.d.ts +16 -0
- package/dist/esm/resources/types.d.ts.map +1 -1
- package/dist/esm/units.d.ts.map +1 -1
- package/dist/esm/units.js +18 -2
- package/dist/esm/units.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/concepts.md +193 -0
- package/docs/errors.md +491 -0
- package/package.json +7 -6
- package/src/client.ts +89 -25
- package/src/core/errors.ts +49 -15
- package/src/core/gated.ts +31 -7
- package/src/core/http.ts +173 -49
- package/src/core/pagination.ts +38 -1
- package/src/generated/operations.ts +1 -1
- package/src/generated/types.ts +1001 -180
- package/src/index.ts +64 -7
- package/src/resources/addresses.ts +24 -8
- package/src/resources/admin.ts +186 -33
- package/src/resources/approvals.ts +55 -9
- package/src/resources/balances.ts +186 -14
- package/src/resources/categories.ts +125 -30
- package/src/resources/counterparties.ts +23 -6
- package/src/resources/folders.ts +74 -18
- package/src/resources/history.ts +27 -2
- package/src/resources/me.ts +30 -5
- package/src/resources/members.ts +26 -7
- package/src/resources/operations.ts +73 -8
- package/src/resources/registries.ts +90 -11
- package/src/resources/reports.ts +348 -67
- package/src/resources/sharing.ts +71 -18
- package/src/resources/transfers.ts +51 -7
- package/src/resources/types.ts +16 -0
- package/src/units.ts +19 -2
- package/src/version.ts +1 -1
package/dist/esm/units.js
CHANGED
|
@@ -23,8 +23,15 @@ export class AmountError extends Error {
|
|
|
23
23
|
}
|
|
24
24
|
const RAW_RE = /^-?\d+$/;
|
|
25
25
|
const DECIMAL_RE = /^-?\d+(\.\d+)?$/;
|
|
26
|
+
/**
|
|
27
|
+
* The API's own ceiling: `CreateTokenBody.decimals` is `int().min(0).max(38)`
|
|
28
|
+
* in the policy engine's `src/openapi/models.ts`. A lower bound here would
|
|
29
|
+
* contradict the rest of the package — `registries.createToken` would accept a
|
|
30
|
+
* token this module then refuses to do arithmetic on.
|
|
31
|
+
*/
|
|
32
|
+
const MAX_DECIMALS = 38;
|
|
26
33
|
function assertDecimals(decimals) {
|
|
27
|
-
if (!Number.isInteger(decimals) || decimals < 0 || decimals >
|
|
34
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_DECIMALS) {
|
|
28
35
|
throw new AmountError(`Invalid decimals: ${decimals}`);
|
|
29
36
|
}
|
|
30
37
|
}
|
|
@@ -76,8 +83,17 @@ export function toDecimalString(a, options = {}) {
|
|
|
76
83
|
*/
|
|
77
84
|
export function format(a, options = {}) {
|
|
78
85
|
const decimal = toDecimalString(a, { trim: false });
|
|
86
|
+
// The padding is clamped to `decimals` because `decimals` is the maximum
|
|
87
|
+
// below, and Intl throws RangeError when a minimum exceeds its maximum. So
|
|
88
|
+
// the default of two digits made `format` unusable — not merely unpadded —
|
|
89
|
+
// for any token with 0 or 1 decimals, and such tokens are reachable: the API
|
|
90
|
+
// allows `decimals: 0` on a token, and a `currency` category field takes
|
|
91
|
+
// `scale: 0` today. Clamping rather than raising the maximum: digits past
|
|
92
|
+
// `decimals` do not exist in the asset, and printing them would claim a
|
|
93
|
+
// divisibility the token does not have.
|
|
94
|
+
const minFraction = Math.min(options.minFractionDigits ?? 2, a.decimals);
|
|
79
95
|
const formatter = new Intl.NumberFormat(options.locale ?? 'en-US', {
|
|
80
|
-
minimumFractionDigits:
|
|
96
|
+
minimumFractionDigits: minFraction,
|
|
81
97
|
maximumFractionDigits: a.decimals,
|
|
82
98
|
});
|
|
83
99
|
// The runtime accepts a string and keeps precision; lib.es5 still types the
|
package/dist/esm/units.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"units.js","sourceRoot":"","sources":["../../src/units.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;IAC3B,CAAC;CACF;AAED,MAAM,MAAM,GAAG,SAAS,CAAA;AACxB,MAAM,UAAU,GAAG,iBAAiB,CAAA;AAEpC,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"units.js","sourceRoot":"","sources":["../../src/units.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** SDK version, sent in the `user-agent` header. */
|
|
2
|
-
export declare const SDK_VERSION = "0.1
|
|
2
|
+
export declare const SDK_VERSION = "0.2.1";
|
|
3
3
|
/** Default API base URL. */
|
|
4
4
|
export declare const DEFAULT_BASE_URL = "https://policy-engine-rest.ezig.workers.dev";
|
|
5
5
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/esm/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** SDK version, sent in the `user-agent` header. */
|
|
2
|
-
export const SDK_VERSION = '0.1
|
|
2
|
+
export const SDK_VERSION = '0.2.1';
|
|
3
3
|
/** Default API base URL. */
|
|
4
4
|
export const DEFAULT_BASE_URL = 'https://policy-engine-rest.ezig.workers.dev';
|
|
5
5
|
//# sourceMappingURL=version.js.map
|
package/docs/concepts.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Concepts
|
|
2
|
+
|
|
3
|
+
The API behind this SDK is a custody system: it holds addresses, moves money under rules, and
|
|
4
|
+
records who decided what. Most of the surprises in it come from five ideas. Knowing them makes the
|
|
5
|
+
rest of the package read as obvious; not knowing them is how an interface ends up telling someone
|
|
6
|
+
their money has left when it has not.
|
|
7
|
+
|
|
8
|
+
## 1. A vault is the unit of everything
|
|
9
|
+
|
|
10
|
+
A vault owns addresses, counterparties, policies, categories and reports. Almost every path is
|
|
11
|
+
`/vaults/{code}/…`, and nothing crosses a vault boundary.
|
|
12
|
+
|
|
13
|
+
In the SDK that is `core.vault(code)`, created where it is used rather than stored:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
core.vault('alpha').addresses.list()
|
|
17
|
+
core.vault('beta').addresses.list()
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
There is no "current vault". An administrator works with several at once, the active one changes at
|
|
21
|
+
runtime in both our clients, and a remembered scope would mean requests to the wrong vault after a
|
|
22
|
+
switch — a failure mode with no symptom until the figures are wrong.
|
|
23
|
+
|
|
24
|
+
## 2. Two tiers of authorisation, and they do not substitute for each other
|
|
25
|
+
|
|
26
|
+
This is the distinction most often confused in this system.
|
|
27
|
+
|
|
28
|
+
| | **Policy** | **Grant** |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| Answers | may this ACTION happen? | is there access to this OBJECT? |
|
|
31
|
+
| Input | action plus request context — amount, recipient, path, history | a pair: subject and resource |
|
|
32
|
+
| Nature | computed every time | a fact, stored as a row |
|
|
33
|
+
| Outcomes | three: allow / block / require approval | binary: yes or no |
|
|
34
|
+
|
|
35
|
+
They compose. Sending a transfer first needs the address right (a grant) and then clears the engine
|
|
36
|
+
(a policy). Removing either does not simplify anything — they answer different questions.
|
|
37
|
+
|
|
38
|
+
Practical consequences you will meet:
|
|
39
|
+
|
|
40
|
+
- the counterparty directory does **not** restrict where money can go. A transfer accepts any
|
|
41
|
+
address; the directory only attaches a name afterwards. Restricting recipients is a policy of the
|
|
42
|
+
form `block + not(...)`;
|
|
43
|
+
- policies are loaded only from the initiator's groups. An allow-list added to one group does not
|
|
44
|
+
apply to members of another, so a list meant for everyone has to exist in every transfer group;
|
|
45
|
+
- visibility is a grant too, and the default is deny. A member sees only themselves until someone
|
|
46
|
+
grants otherwise, which is why an empty directory usually means "no visibility grants yet" rather
|
|
47
|
+
than "no members".
|
|
48
|
+
|
|
49
|
+
## 3. An operation may not happen — it may go for approval
|
|
50
|
+
|
|
51
|
+
Transfers, address creation, changes to the counterparty directory and gated labelling all pass
|
|
52
|
+
through the policy engine, and the engine has three outcomes, not two.
|
|
53
|
+
|
|
54
|
+
The API expresses this with the HTTP status, because **the response bodies are identical**:
|
|
55
|
+
|
|
56
|
+
| Status | Meaning |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| 201 | applied — it happened |
|
|
59
|
+
| 202 | pending — funds are RESERVED, nothing has moved, there is a request to sign |
|
|
60
|
+
| 200 | replayed — the same idempotency key; the transfer already existed, in whatever state it is now |
|
|
61
|
+
|
|
62
|
+
The SDK turns that into `Gated`:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
switch (result.outcome) {
|
|
66
|
+
case 'applied': return toast('Transfer sent')
|
|
67
|
+
case 'pending': return toast('Awaiting signatures — funds are reserved')
|
|
68
|
+
case 'replayed': return toast(describeStatus(result.data.transaction.status))
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`replayed` is kept apart from `applied` on purpose: a replay means the previous attempt reached the
|
|
73
|
+
server and only the answer was lost — not that it succeeded. The body is that transfer as it stands
|
|
74
|
+
now, so `replayed` must not be shown as "sent": `data.transaction.status` says whether it went out
|
|
75
|
+
(`confirmed`, or `submitted`), is waiting for signatures (`awaiting_approval`), is still executing
|
|
76
|
+
(`pending`) or did not go out (`failed`, `rejected`, `cancelled`).
|
|
77
|
+
|
|
78
|
+
**Only `transfers.send` can return it.** `idempotencyKey` exists on exactly one request body in the
|
|
79
|
+
whole API — the transfer — so it is the only place where a 200 means "this already happened". On
|
|
80
|
+
every other gated method a 200 is an ordinary success (updating a counterparty, for instance) and
|
|
81
|
+
is labelled `applied`; writing a `case 'replayed'` there is harmless but dead. The branch is worth
|
|
82
|
+
handling where it is reachable and worth knowing about where it is not, because "the key protects
|
|
83
|
+
the retry" is true of transfers and of nothing else: a timed-out counterparty change has to be
|
|
84
|
+
verified by reading the object back.
|
|
85
|
+
|
|
86
|
+
Two further rules about approvals:
|
|
87
|
+
|
|
88
|
+
- **who may vote is a snapshot.** It is taken when the request is created, from the policies as
|
|
89
|
+
they stood then. Editing a policy or a group afterwards does not change a request in flight —
|
|
90
|
+
deliberately, so that a change of rules cannot retroactively unlock money already reserved;
|
|
91
|
+
- **requirements are collected from every applicable policy**, not resolved to the strictest one.
|
|
92
|
+
That is how "the CFO AND compliance" is expressed, and it means adding a permissive policy beside
|
|
93
|
+
an existing one does not remove its signatures.
|
|
94
|
+
|
|
95
|
+
## 4. Money is a string, and zero is not nothing
|
|
96
|
+
|
|
97
|
+
Every amount is raw smallest units in a string: `"96325670000"` is 96 325.67 USDT. `float64` loses
|
|
98
|
+
precision above 2⁵³, and balances here exceed that.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { amount, format, add, parseDecimal } from '@v3finance/core-sdk'
|
|
102
|
+
|
|
103
|
+
const balance = amount(address.balance ?? '0', 6, 'usdt')
|
|
104
|
+
format(balance, { withAsset: true }) // "96,325.67 USDT"
|
|
105
|
+
add(balance, parseDecimal('2.5', 6))
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
There is no `toNumber`. It would be a convenient door into exactly the bug this layer exists to
|
|
109
|
+
prevent.
|
|
110
|
+
|
|
111
|
+
**Where it is decimal instead.** "Raw" above describes what the API ANSWERS with — addresses,
|
|
112
|
+
transfers, deposits, balances, the ledger. Three places are decimal, and one of them is an INPUT
|
|
113
|
+
where a mistake moves money:
|
|
114
|
+
|
|
115
|
+
- **the `amount` you send to `transfers.send` is DECIMAL** — `'1.5'` means one and a half USDT, and
|
|
116
|
+
the API scales it by the token's decimals. Sending the raw figure `'1500000'` there asks for a
|
|
117
|
+
million and a half. The same holds for `context.amount.value` in `registries.evaluate`;
|
|
118
|
+
- the figures inside a report are decimal strings in units of the asset — `"1.5"`, already scaled.
|
|
119
|
+
The one raw figure in a report is `balanceRaw`, in the opening and closing balances of
|
|
120
|
+
`address_activity`;
|
|
121
|
+
- the totals of `balances.asOf()` are decimal, although the same-named fields of `balances.list()`
|
|
122
|
+
are raw.
|
|
123
|
+
|
|
124
|
+
`amount()` would misread a decimal: it rejects `"1.5"` outright and takes `"15"` for fifteen
|
|
125
|
+
smallest units. Read decimals with `parseDecimal`, and convert before sending — never pass a raw
|
|
126
|
+
string where a decimal is expected, or the other way round.
|
|
127
|
+
|
|
128
|
+
**`balance: null` is not zero.** It means the address has no ledger account yet — nothing has ever
|
|
129
|
+
arrived. "No account" and "empty account" deserve different wording, and merging them produces an
|
|
130
|
+
interface that claims an address is empty when it has never been used.
|
|
131
|
+
|
|
132
|
+
Underneath, balances are derived from a double-entry ledger, which is the single source of truth:
|
|
133
|
+
no balance is stored on an address. A token with no ledger account simply does not appear in
|
|
134
|
+
`balances[]`, for the same reason.
|
|
135
|
+
|
|
136
|
+
The ledger is append-only. A correction is a reversing entry, never an edit.
|
|
137
|
+
|
|
138
|
+
## 5. Shared access: roles out, flags in
|
|
139
|
+
|
|
140
|
+
An address or a folder can be shared. Outwards the right is a **role**, inwards it is flags:
|
|
141
|
+
|
|
142
|
+
- `viewer` — can see;
|
|
143
|
+
- `contributor` — can see and transfer.
|
|
144
|
+
|
|
145
|
+
There is no "manager" role, because that is the creator of the object: one person, not something a
|
|
146
|
+
grant hands out.
|
|
147
|
+
|
|
148
|
+
Granting is idempotent — repeating it for the same pair updates the rights and revives a revoked
|
|
149
|
+
grant — and revoking is soft and immediate.
|
|
150
|
+
|
|
151
|
+
A folder and an address group are **one entity** served under two prefixes; this package uses
|
|
152
|
+
`/address-folders`. Two rules protect it from leaking somebody else's address:
|
|
153
|
+
|
|
154
|
+
- only the creator changes a folder's contents, and only with their own addresses;
|
|
155
|
+
- an owner can always pull their own address out of someone else's folder.
|
|
156
|
+
|
|
157
|
+
## Labelling and reports, in one paragraph each
|
|
158
|
+
|
|
159
|
+
**Operation categories** are a configurable schema: which categories exist and what fields they
|
|
160
|
+
have is visible to every member, while the *values* on operations are restricted and managing the
|
|
161
|
+
schema is administrator-only. A category key and a field's key and type are immutable once created,
|
|
162
|
+
because values, reports and snapshots refer to them; a field with history is archived, not deleted.
|
|
163
|
+
Whether editing values needs approval is a property of the category (`approvalScope`), not of the
|
|
164
|
+
policy engine — looking for it there is wasted time.
|
|
165
|
+
|
|
166
|
+
**Reports** come in ten types, and each answers with its own shape — a position report has no
|
|
167
|
+
turnover summary, an approval report counts requests rather than money — so `reports.run(type, …)`
|
|
168
|
+
is typed per report. They answer in their own error envelope with `REPORT_*` codes, which is
|
|
169
|
+
intentional. Sensitive field values are redacted per operation by the loader according to what the
|
|
170
|
+
caller may see: the value becomes `null` and its key appears in `redactedFields`. Access to an
|
|
171
|
+
operation and access to its sensitive labelling are different rights — the first comes with
|
|
172
|
+
`view`, the second only with `transfer`.
|
|
173
|
+
|
|
174
|
+
## Authentication
|
|
175
|
+
|
|
176
|
+
One way in: a magic link by email. Signing up is possible only on an administrator's invitation, so
|
|
177
|
+
requesting a link for an uninvited address creates nothing.
|
|
178
|
+
|
|
179
|
+
The session travels in one of three ways, and the SDK supports all three because it stores none of
|
|
180
|
+
them — you supply headers, it hands two events back:
|
|
181
|
+
|
|
182
|
+
| Runtime | How |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| Browser | `credentials: 'include'`, cookie set by the server |
|
|
185
|
+
| React Native | your own cookie jar, returned from `getAuthHeaders` |
|
|
186
|
+
| Anywhere | `Authorization: Bearer <session-token>` |
|
|
187
|
+
|
|
188
|
+
In bearer mode `onTokenRotated` is **required**: the server extends a session through the
|
|
189
|
+
`set-auth-token` header, and a client that does not store the new token is signed out at the next
|
|
190
|
+
rotation.
|
|
191
|
+
|
|
192
|
+
There is no API key and no machine-to-machine flow today. An integration that needs to run without
|
|
193
|
+
a person signing in cannot authenticate yet.
|