@cardano-slips/flow 0.1.0 → 0.3.0

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.
Files changed (113) hide show
  1. package/README.md +53 -9
  2. package/dist/address.d.ts +12 -0
  3. package/dist/address.d.ts.map +1 -1
  4. package/dist/address.js +43 -0
  5. package/dist/address.js.map +1 -1
  6. package/dist/balance-error.d.ts +48 -0
  7. package/dist/balance-error.d.ts.map +1 -0
  8. package/dist/balance-error.js +45 -0
  9. package/dist/balance-error.js.map +1 -0
  10. package/dist/balance.d.ts +54 -0
  11. package/dist/balance.d.ts.map +1 -0
  12. package/dist/balance.js +175 -0
  13. package/dist/balance.js.map +1 -0
  14. package/dist/card.css +492 -0
  15. package/dist/card.d.ts +41 -0
  16. package/dist/card.d.ts.map +1 -0
  17. package/dist/card.js +69 -0
  18. package/dist/card.js.map +1 -0
  19. package/dist/cip30.d.ts +10 -0
  20. package/dist/cip30.d.ts.map +1 -1
  21. package/dist/cip30.js +16 -0
  22. package/dist/cip30.js.map +1 -1
  23. package/dist/complete-error.d.ts +57 -0
  24. package/dist/complete-error.d.ts.map +1 -0
  25. package/dist/complete-error.js +52 -0
  26. package/dist/complete-error.js.map +1 -0
  27. package/dist/complete.d.ts +77 -0
  28. package/dist/complete.d.ts.map +1 -0
  29. package/dist/complete.js +182 -0
  30. package/dist/complete.js.map +1 -0
  31. package/dist/derived.d.ts +8 -0
  32. package/dist/derived.d.ts.map +1 -0
  33. package/dist/derived.js +2 -0
  34. package/dist/derived.js.map +1 -0
  35. package/dist/effects-panel.d.ts +37 -0
  36. package/dist/effects-panel.d.ts.map +1 -0
  37. package/dist/effects-panel.js +64 -0
  38. package/dist/effects-panel.js.map +1 -0
  39. package/dist/effects.css +629 -0
  40. package/dist/exchange.d.ts +54 -0
  41. package/dist/exchange.d.ts.map +1 -0
  42. package/dist/exchange.js +136 -0
  43. package/dist/exchange.js.map +1 -0
  44. package/dist/explain.d.ts +39 -0
  45. package/dist/explain.d.ts.map +1 -0
  46. package/dist/explain.js +172 -0
  47. package/dist/explain.js.map +1 -0
  48. package/dist/index.d.ts +34 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +19 -2
  51. package/dist/index.js.map +1 -1
  52. package/dist/ledger.d.ts +74 -0
  53. package/dist/ledger.d.ts.map +1 -0
  54. package/dist/ledger.js +402 -0
  55. package/dist/ledger.js.map +1 -0
  56. package/dist/outcome-panel.d.ts +63 -0
  57. package/dist/outcome-panel.d.ts.map +1 -0
  58. package/dist/outcome-panel.js +40 -0
  59. package/dist/outcome-panel.js.map +1 -0
  60. package/dist/parameter-form.d.ts +26 -0
  61. package/dist/parameter-form.d.ts.map +1 -0
  62. package/dist/parameter-form.js +42 -0
  63. package/dist/parameter-form.js.map +1 -0
  64. package/dist/resolve.d.ts +11 -0
  65. package/dist/resolve.d.ts.map +1 -0
  66. package/dist/resolve.js +21 -0
  67. package/dist/resolve.js.map +1 -0
  68. package/dist/sign-error.d.ts +62 -0
  69. package/dist/sign-error.d.ts.map +1 -0
  70. package/dist/sign-error.js +42 -0
  71. package/dist/sign-error.js.map +1 -0
  72. package/dist/sign.d.ts +38 -0
  73. package/dist/sign.d.ts.map +1 -0
  74. package/dist/sign.js +79 -0
  75. package/dist/sign.js.map +1 -0
  76. package/dist/slip-card.d.ts +55 -0
  77. package/dist/slip-card.d.ts.map +1 -0
  78. package/dist/slip-card.js +89 -0
  79. package/dist/slip-card.js.map +1 -0
  80. package/dist/tokens.css +97 -123
  81. package/dist/utxo.d.ts +16 -0
  82. package/dist/utxo.d.ts.map +1 -0
  83. package/dist/utxo.js +51 -0
  84. package/dist/utxo.js.map +1 -0
  85. package/dist/witness.d.ts +23 -0
  86. package/dist/witness.d.ts.map +1 -0
  87. package/dist/witness.js +101 -0
  88. package/dist/witness.js.map +1 -0
  89. package/package.json +13 -6
  90. package/src/address.ts +53 -0
  91. package/src/balance-error.ts +77 -0
  92. package/src/balance.ts +285 -0
  93. package/src/card.css +492 -0
  94. package/src/card.ts +86 -0
  95. package/src/cip30.ts +19 -0
  96. package/src/complete-error.ts +95 -0
  97. package/src/complete.ts +307 -0
  98. package/src/derived.ts +8 -0
  99. package/src/effects-panel.tsx +386 -0
  100. package/src/effects.css +629 -0
  101. package/src/exchange.ts +212 -0
  102. package/src/explain.ts +211 -0
  103. package/src/index.ts +64 -3
  104. package/src/ledger.ts +503 -0
  105. package/src/outcome-panel.tsx +263 -0
  106. package/src/parameter-form.tsx +138 -0
  107. package/src/resolve.ts +40 -0
  108. package/src/sign-error.ts +89 -0
  109. package/src/sign.ts +118 -0
  110. package/src/slip-card.tsx +244 -0
  111. package/src/tokens.css +97 -123
  112. package/src/utxo.ts +70 -0
  113. package/src/witness.ts +132 -0
package/README.md CHANGED
@@ -30,6 +30,51 @@ These components are meant to be dropped into someone else's page. No fixed posi
30
30
 
31
31
  React is a **peer** dependency: your copy is the one that renders, and a second copy in the tree is the oldest breakage in the ecosystem.
32
32
 
33
+ ## Components
34
+
35
+ ```tsx
36
+ import { SlipCard } from "@cardano-slips/flow"
37
+ import "@cardano-slips/flow/tokens.css"
38
+ import "@cardano-slips/flow/card.css"
39
+
40
+ <SlipCard slip={slip} discoveryUrl={url} onSubmit={({ href, values }) => …} />
41
+ ```
42
+
43
+ `SlipCard` renders what the endpoint declared — icon, title, description, and a button per linked action — generates the form its parameters describe, and hands you the `POST` target once every value passes. `SlipCardSkeleton` holds the same box while the metadata is in flight; `SlipCardError` replaces it when the endpoint never answered.
44
+
45
+ The card makes no claim about the transaction. Title and description are the publisher's words, and checking them against what the transaction actually does is the effects panel's job — against the bytes, not against this card.
46
+
47
+ Nothing here decides for a person on the endpoint's behalf: a value that fails `required`, `min` or `max` is caught before anything is sent, in `core`'s own sentence, so the same bad value reads identically in every client. A field the endpoint itself refuses lands on that field and leaves the card standing, and what was typed stays typed.
48
+
49
+ ### Restyling
50
+
51
+ `card.css` is optional. Import it and you get the design sheet; skip it and you get the markup, where every element carries a class of ours and nothing else:
52
+
53
+ | Class | What it is |
54
+ | --- | --- |
55
+ | `slip-card` | the card, and `slip-card--loading` / `slip-card--failed` for the other two; `data-closed` marks a Slip that cannot be signed and `data-busy` one with a request in flight |
56
+ | `slip-card__head`, `__icon`, `__title`, `__origin`, `__description` | what the endpoint declared |
57
+ | `slip-card__actions`, `__action` | the buttons; `data-primary` marks the one that is emphasised |
58
+ | `slip-card__reason`, `__note` | why an action is closed, and the promise the card makes |
59
+ | `slip-fields`, `slip-field`, `slip-field__*` | the generated form; `data-invalid` marks a field that was rejected |
60
+
61
+ The card is the publisher's surface and is meant to be restyled. The chrome that judges it — the effects panel, the mismatch block, the network indicator — is not, hosted or self-hosted: a publisher who can restyle the surface that judges them makes the verdict look like something they control.
62
+
63
+ ### The effects panel
64
+
65
+ ```tsx
66
+ import { EffectsPanel } from "@cardano-slips/flow"
67
+ import "@cardano-slips/flow/effects.css"
68
+
69
+ <EffectsPanel claim={action.label} derived={attempt} verdict={{ _tag: "match" }} onSign={…} onCancel={…} />
70
+ ```
71
+
72
+ `EffectsPanel` shows what a transaction does, read from its own bytes: the figure the person is deciding on, then one row per effect — payments, tokens received, withdrawals, certificates, the fee, and deposits and refunds, each marked refundable where the ledger guarantees it and as stated where only the transaction claims it. `derived` is what `completeIntent` hands `onAttempt`, or what a `Blocked` refusal carries.
73
+
74
+ `verdict` is the verifier's own and is required. On a mismatch the sign button is not rendered at all — the claim is set beside what the transaction does, the one row the link never described is marked, and the only ways out are closing it and reporting the link. There is no prop that brings the button back. The countdown takes the headline's place under a minute, and an expired transaction offers `onRebuild` instead of a signature.
75
+
76
+ `effects.css` is the fixed chrome above: import it as it is.
77
+
33
78
  ## Tokens
34
79
 
35
80
  ```ts
@@ -38,24 +83,23 @@ import "@cardano-slips/flow/tokens.css"
38
83
 
39
84
  ```html
40
85
  <div class="slip-root">…</div>
41
- <div class="slip-root" data-theme="dark">…</div>
42
86
  ```
43
87
 
44
- The tokens are scoped to `slip-root` rather than `:root`, because a package that writes `--ink` onto the document redefines whatever the host already called that. Put the class on the element that wraps the Slip. There is no reset in the file and no rule that selects an element, so an inherited font stack stays where it is until something of ours asks for a token.
88
+ The tokens are scoped to `slip-root` rather than `:root`, because a package that writes `--ink` onto the document redefines whatever the host already called that. Every component of ours puts the class on its own root, so an embedded card carries its tokens with it. There is no reset in the file and no rule that selects an element, so an inherited font stack stays where it is until something of ours asks for a token.
45
89
 
46
- `data-theme="dark"` is the whole of the theme rule: it rebinds the roles — surfaces, ink, accent and the semantic three — so a component writes `var(--ink)` once and is right in both. A component choosing between a light token and a dark one is a component deciding the rule, and two of them will decide it differently. Whether dark follows the operating system is not settled by the design sheet, so it is not decided here either; the attribute is the only way in.
47
-
48
- Three families of surface, and the difference is the point:
90
+ There is one theme. The design sheet collapsed an earlier light/dark pair into a single ground that leans light, so there is no `data-theme` and no role that means two things — a component that can ask which theme it is in is a component that will answer differently from the next one. What carries the weight instead is that the three families of surface are genuinely different surfaces:
49
91
 
50
92
  | Family | What it is |
51
93
  | --- | --- |
52
94
  | `--page`, `--card` | the ordinary ground, and what lifts off it |
53
- | `--vault-*` | the transaction preview, which separates itself by surface and border rather than by being dark |
54
- | `--dark-*` | code blocks and the Open Graph card — dark in **both** themes, so they are the one thing the theme does not touch |
95
+ | `--vault-*` | the transaction preview, on slate — the one grave surface, and the reason the rest can stay bright |
96
+ | `--dark-*` | code blocks and the Open Graph card, fixed wherever they appear because neither sits on a ground we control |
97
+
98
+ There is one typeface, Poppins, and one token naming it. The package does not fetch it — a stylesheet that reaches a third-party CDN makes a privacy and performance decision that belongs to whoever owns the page — so load Poppins yourself, or take the `system-ui` the stack falls back to. Type arrives as whole roles — `font: var(--type-card-title)` carries family, weight, size and line-height together — because a role is a pairing, not a size, and because a component that can apply the size without the family is a component that will. What separates a title from a label is weight and size; there is no second face to reach for, and `--type-technical` is the role for text meant for a machine — an address, a hash, an error code.
55
99
 
56
- Type arrives as whole roles — `font: var(--type-card-title)` carries family, weight, size and line-height together — because the sheet settles a pairing, not a size. Depth is a border; there is no shadow token.
100
+ Depth is a border; there is no shadow token. Buttons are outlined rather than filled: the accent is the label and the edge, not the ground.
57
101
 
58
- Two rules the tests keep: no colour is written anywhere but `tokens.css`, and the design sheet's contrast audit is recomputed against these values rather than trusted. `--accent-fill` is a fill — it does not clear AA on a light card, which is why `--accent-text` exists for any accent-coloured word, and it stays a fill in the dark theme where the ratio alone would allow otherwise.
102
+ Three rules the tests keep: no colour is written anywhere but `tokens.css`, every `var(--…)` a stylesheet reaches for is a token that exists, and the design sheet's contrast audit is recomputed against these values rather than trusted — which is how `--vault-bad` came to be a shade lighter here than on the sheet, where the value drawn measures 4.42:1 on the preview surface under a row labelled a pass. `--accent-fill` is a fill — it does not clear AA on a light card, which is why `--accent-text` exists for any accent-coloured word, and it stays a fill on the preview surface where the ratio alone would allow otherwise.
59
103
 
60
104
  ## Entry point
61
105
 
package/dist/address.d.ts CHANGED
@@ -10,4 +10,16 @@ export type WalletAddress = {
10
10
  * browser extension chose to send, and every refusal reaches a person as words.
11
11
  */
12
12
  export declare const readWalletAddress: (hex: string) => Either.Either<WalletAddress, string>;
13
+ export type OwnAddress = {
14
+ /** Raw, as the verifier compares them against the body's addresses. */
15
+ readonly bytes: Uint8Array;
16
+ /** Absent for a Byron address, whose header carries no network. */
17
+ readonly networkId?: NetworkId;
18
+ };
19
+ /**
20
+ * Reads an address the wallet calls its own: any payment address, a reward
21
+ * account, or a Byron address an old wallet still reports as used. Refusing
22
+ * the Byron one would stop the whole flow over an address nothing here spends.
23
+ */
24
+ export declare const readOwnAddress: (hex: unknown) => Either.Either<OwnAddress, string>;
13
25
  //# sourceMappingURL=address.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAEvC,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,CAAA;AAE7B,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;CAC9B,CAAA;AA0BD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAqBlF,CAAA"}
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAEvC,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,CAAA;AAE7B,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;CAC9B,CAAA;AA0BD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAqBlF,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAC/B,CAAA;AAkBD;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAuB7E,CAAA"}
package/dist/address.js CHANGED
@@ -51,4 +51,47 @@ export const readWalletAddress = (hex) => {
51
51
  onRight: () => Either.right({ bech32, networkId: networkId })
52
52
  });
53
53
  };
54
+ const BYRON_TYPE = 8;
55
+ const FIRST_REWARD_TYPE = 14;
56
+ const LAST_REWARD_TYPE = 15;
57
+ /** A header byte and one or two 28-byte hashes. */
58
+ const shelleyLengths = {
59
+ 0: [57],
60
+ 1: [57],
61
+ 2: [57],
62
+ 3: [57],
63
+ 6: [29],
64
+ 7: [29],
65
+ 14: [29],
66
+ 15: [29]
67
+ };
68
+ /**
69
+ * Reads an address the wallet calls its own: any payment address, a reward
70
+ * account, or a Byron address an old wallet still reports as used. Refusing
71
+ * the Byron one would stop the whole flow over an address nothing here spends.
72
+ */
73
+ export const readOwnAddress = (hex) => {
74
+ // Typed as hex by CIP-30, and sent by an extension under no obligation to.
75
+ const raw = typeof hex === "string" ? fromHex(hex.trim()) : undefined;
76
+ if (raw === undefined)
77
+ return refuse(`${String(hex).slice(0, 16)}… is not hex`);
78
+ const bytes = unwrapCbor(raw);
79
+ const header = bytes[0];
80
+ const type = header >> 4;
81
+ if (type === BYRON_TYPE)
82
+ return Either.right({ bytes });
83
+ const networkId = header & 0x0f;
84
+ if (networkId !== 0 && networkId !== 1)
85
+ return refuse(`the address header names network ${networkId}`);
86
+ const payment = type <= LAST_PAYMENT_TYPE;
87
+ const reward = type >= FIRST_REWARD_TYPE && type <= LAST_REWARD_TYPE;
88
+ if (!payment && !reward)
89
+ return refuse(`address type ${type} is not one a wallet holds`);
90
+ // Pointer addresses (4, 5) end in variable-length integers, so only a floor applies.
91
+ const lengths = shelleyLengths[type];
92
+ const fits = lengths === undefined ? bytes.length > 29 : lengths.includes(bytes.length);
93
+ if (!fits)
94
+ return refuse(`${bytes.length} bytes is the wrong length for address type ${type}`);
95
+ return Either.right({ bytes, networkId: networkId });
96
+ };
54
97
  //# sourceMappingURL=address.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Why an intent did not become a transaction. Every refusal carries a spec
3
+ * error code, because each one is a failure of the exchange the spec describes
4
+ * rather than a state of a browser extension (`wallet-error.ts` is the other
5
+ * half, and deliberately has refusals that carry no code).
6
+ */
7
+ import { type ClientErrorCode } from "@cardano-slips/core";
8
+ export type BalanceRefusal =
9
+ /** `validUntil` has already passed. A fresh POST returns a fresh intent. */
10
+ "IntentExpired"
11
+ /** An address in the intent encodes a different network from the Slip's. */
12
+ | "ForeignAddress"
13
+ /** A certificate or withdrawal needs the wallet's stake credential and the address carries none. */
14
+ | "NoStakeCredential"
15
+ /** The change address the wallet gave is not an address these bytes can be read as. */
16
+ | "UnreadableChangeAddress"
17
+ /** The intent withdraws rewards and nobody said what the reward balance is. */
18
+ | "RewardBalanceUnknown"
19
+ /** The wallet cannot cover the intent, the minimum ADA its outputs require, and the fee. */
20
+ | "InsufficientFunds"
21
+ /** The intent cannot be built into a valid transaction for any other reason. */
22
+ | "CannotBalance";
23
+ /**
24
+ * Exhaustive by type: adding a refusal above without listing it here fails to
25
+ * compile, and `test/balance.test.ts` fails if any of them stops being reachable.
26
+ */
27
+ export declare const balanceRefusals: Readonly<Record<BalanceRefusal, true>>;
28
+ /**
29
+ * A wrong-network address is `MALFORMED_RESPONSE` and not `WRONG_NETWORK`:
30
+ * the latter is a disagreement the person can act on by switching wallets, and
31
+ * an endpoint that sent an address on another chain is not one of those.
32
+ */
33
+ export declare const slipErrorCodeFor: (refusal: BalanceRefusal) => ClientErrorCode;
34
+ declare const BalanceError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
35
+ readonly _tag: "BalanceError";
36
+ } & Readonly<A>;
37
+ /** `cause` keeps what evolution-sdk said, so a build failure stays diagnosable. */
38
+ export declare class BalanceError extends BalanceError_base<{
39
+ readonly refusal: BalanceRefusal;
40
+ readonly detail: string;
41
+ readonly cause?: unknown;
42
+ }> {
43
+ get message(): string;
44
+ get code(): ClientErrorCode;
45
+ }
46
+ export declare const refuse: (refusal: BalanceRefusal, detail: string, cause?: unknown) => BalanceError;
47
+ export {};
48
+ //# sourceMappingURL=balance-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balance-error.d.ts","sourceRoot":"","sources":["../src/balance-error.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAG1D,MAAM,MAAM,cAAc;AACxB,4EAA4E;AAC1E,eAAe;AACjB,4EAA4E;GAC1E,gBAAgB;AAClB,oGAAoG;GAClG,mBAAmB;AACrB,uFAAuF;GACrF,yBAAyB;AAC3B,+EAA+E;GAC7E,sBAAsB;AACxB,4FAA4F;GAC1F,mBAAmB;AACrB,gFAAgF;GAC9E,eAAe,CAAA;AAEnB;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,CAQlE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,cAAc,KAAG,eAc1D,CAAA;;;;AAED,mFAAmF;AACnF,qBAAa,YAAa,SAAQ,kBAAiC;IACjE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAE7B;IAED,IAAI,IAAI,IAAI,eAAe,CAE1B;CACF;AAED,eAAO,MAAM,MAAM,GAAI,SAAS,cAAc,EAAE,QAAQ,MAAM,EAAE,QAAQ,OAAO,KAAG,YACA,CAAA"}
@@ -0,0 +1,45 @@
1
+ import { Data } from "effect";
2
+ /**
3
+ * Exhaustive by type: adding a refusal above without listing it here fails to
4
+ * compile, and `test/balance.test.ts` fails if any of them stops being reachable.
5
+ */
6
+ export const balanceRefusals = {
7
+ IntentExpired: true,
8
+ ForeignAddress: true,
9
+ NoStakeCredential: true,
10
+ UnreadableChangeAddress: true,
11
+ RewardBalanceUnknown: true,
12
+ InsufficientFunds: true,
13
+ CannotBalance: true
14
+ };
15
+ /**
16
+ * A wrong-network address is `MALFORMED_RESPONSE` and not `WRONG_NETWORK`:
17
+ * the latter is a disagreement the person can act on by switching wallets, and
18
+ * an endpoint that sent an address on another chain is not one of those.
19
+ */
20
+ export const slipErrorCodeFor = (refusal) => {
21
+ switch (refusal) {
22
+ case "IntentExpired":
23
+ return "INTENT_EXPIRED";
24
+ case "ForeignAddress":
25
+ return "MALFORMED_RESPONSE";
26
+ case "InsufficientFunds":
27
+ return "INSUFFICIENT_FUNDS";
28
+ case "NoStakeCredential":
29
+ case "UnreadableChangeAddress":
30
+ case "RewardBalanceUnknown":
31
+ case "CannotBalance":
32
+ return "CANNOT_BALANCE";
33
+ }
34
+ };
35
+ /** `cause` keeps what evolution-sdk said, so a build failure stays diagnosable. */
36
+ export class BalanceError extends Data.TaggedError("BalanceError") {
37
+ get message() {
38
+ return this.detail;
39
+ }
40
+ get code() {
41
+ return slipErrorCodeFor(this.refusal);
42
+ }
43
+ }
44
+ export const refuse = (refusal, detail, cause) => new BalanceError({ refusal, detail, ...(cause === undefined ? {} : { cause }) });
45
+ //# sourceMappingURL=balance-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balance-error.js","sourceRoot":"","sources":["../src/balance-error.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAkB7B;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2C;IACrE,aAAa,EAAE,IAAI;IACnB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,uBAAuB,EAAE,IAAI;IAC7B,oBAAoB,EAAE,IAAI;IAC1B,iBAAiB,EAAE,IAAI;IACvB,aAAa,EAAE,IAAI;CACpB,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAuB,EAAmB,EAAE;IAC3E,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,eAAe;YAClB,OAAO,gBAAgB,CAAA;QACzB,KAAK,gBAAgB;YACnB,OAAO,oBAAoB,CAAA;QAC7B,KAAK,mBAAmB;YACtB,OAAO,oBAAoB,CAAA;QAC7B,KAAK,mBAAmB,CAAC;QACzB,KAAK,yBAAyB,CAAC;QAC/B,KAAK,sBAAsB,CAAC;QAC5B,KAAK,eAAe;YAClB,OAAO,gBAAgB,CAAA;IAC3B,CAAC;AACH,CAAC,CAAA;AAED,mFAAmF;AACnF,MAAM,OAAO,YAAa,SAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAI/D;IACA,IAAa,OAAO;QAClB,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAuB,EAAE,MAAc,EAAE,KAAe,EAAgB,EAAE,CAC/F,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The privacy-preserving heart of Mode A: the endpoint's half-transaction
3
+ * becomes a whole one here, against unspent outputs it never sees (ADR-0002).
4
+ *
5
+ * Every term arrives as an argument — unspent outputs, protocol parameters, the
6
+ * reward balance, the clock — for the same reason the verifier takes its five:
7
+ * a balancer that fetched them could be made slow, made to fail, or made to
8
+ * answer wrongly by whoever answered.
9
+ */
10
+ import { type Intent, type Network } from "@cardano-slips/core";
11
+ import type { ProtocolParameters } from "@cardano-slips/verifier";
12
+ import { type UTxO } from "@evolution-sdk/evolution";
13
+ import { Effect } from "effect";
14
+ import { type BalanceError } from "./balance-error.js";
15
+ import type { CborHex } from "./cip30.js";
16
+ /**
17
+ * The verifier's parameters plus the one bound the builder needs and the gate
18
+ * does not. One vocabulary across both halves: the figures that balance a
19
+ * transaction are the figures it will be judged against.
20
+ */
21
+ export type BalancingParameters = ProtocolParameters & {
22
+ /** `maxTxSize`: the byte ceiling a built transaction must fit under. */
23
+ readonly maxTxSize: number;
24
+ };
25
+ export type BalanceInputs = {
26
+ readonly intent: Intent;
27
+ /** The Slip's network. Every address in the intent is held to it. */
28
+ readonly network: Network;
29
+ /** Bech32, from the connected wallet. Change returns here. */
30
+ readonly changeAddress: string;
31
+ readonly utxos: ReadonlyArray<UTxO.UTxO>;
32
+ readonly parameters: BalancingParameters;
33
+ /**
34
+ * The whole balance of the wallet's own reward account, required when the
35
+ * intent withdraws rewards. The ledger accepts one figure and only one, and
36
+ * no CIP-30 method answers it.
37
+ */
38
+ readonly rewardBalance?: bigint;
39
+ /** Unix milliseconds. Handed in, so an expiry is decided by one clock and not two. */
40
+ readonly now: number;
41
+ };
42
+ export type BalancedTransaction = {
43
+ /** The complete unsigned transaction: what `verifier` decodes and the wallet signs. */
44
+ readonly cbor: CborHex;
45
+ readonly fee: bigint;
46
+ /** The slot the body expires at, for the rebuild path to watch. */
47
+ readonly ttl: bigint;
48
+ };
49
+ /**
50
+ * Builds the transaction, or says why not. Nothing here asks the network
51
+ * anything, and nothing describing what the wallet holds leaves this function.
52
+ */
53
+ export declare const balanceIntent: (inputs: BalanceInputs) => Effect.Effect<BalancedTransaction, BalanceError>;
54
+ //# sourceMappingURL=balance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../src/balance.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAwC,KAAK,MAAM,EAAE,KAAK,OAAO,EAAe,MAAM,qBAAqB,CAAA;AAClH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAWL,KAAK,IAAI,EACV,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,KAAK,YAAY,EAAU,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG;IACrD,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,CAAA;AAwHD;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,aAAa,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,YAAY,CA4FjG,CAAA"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * The privacy-preserving heart of Mode A: the endpoint's half-transaction
3
+ * becomes a whole one here, against unspent outputs it never sees (ADR-0002).
4
+ *
5
+ * Every term arrives as an argument — unspent outputs, protocol parameters, the
6
+ * reward balance, the clock — for the same reason the verifier takes its five:
7
+ * a balancer that fetched them could be made slow, made to fail, or made to
8
+ * answer wrongly by whoever answered.
9
+ */
10
+ import { addressIsOnNetwork } from "@cardano-slips/core";
11
+ import { Address, Assets, DRep, mainnet, PoolKeyHash, preprod, preview, Schema, Transaction } from "@evolution-sdk/evolution";
12
+ import { makeTxBuilder } from "@evolution-sdk/evolution/sdk/builders/TransactionBuilder";
13
+ import { Effect } from "effect";
14
+ import { refuse } from "./balance-error.js";
15
+ const chains = { mainnet, preprod, preview };
16
+ /**
17
+ * The slot mapping comes from the parameters rather than from the chain preset:
18
+ * the client converts `validUntil` to a slot and the gate converts that slot
19
+ * back to a time, and two mappings would put an honest transaction outside its
20
+ * own declared window.
21
+ */
22
+ const slotConfigOf = ({ slots }) => ({
23
+ zeroTime: slots.time,
24
+ zeroSlot: slots.slot,
25
+ slotLength: Number(slots.slotLength)
26
+ });
27
+ const builderParameters = (parameters) => ({
28
+ minFeeCoefficient: parameters.minFeeCoefficient,
29
+ minFeeConstant: parameters.minFeeConstant,
30
+ coinsPerUtxoByte: parameters.coinsPerUtxoByte,
31
+ maxTxSize: parameters.maxTxSize
32
+ });
33
+ /**
34
+ * What the builder reads for a certificate's deposit. The script fields are
35
+ * zeroed rather than guessed: version 1 builds no transaction that spends from
36
+ * a script, so a cost model here would be a figure nothing computes from.
37
+ */
38
+ const depositParameters = (parameters) => ({
39
+ minFeeA: Number(parameters.minFeeCoefficient),
40
+ minFeeB: Number(parameters.minFeeConstant),
41
+ maxTxSize: parameters.maxTxSize,
42
+ maxValSize: 0,
43
+ keyDeposit: parameters.stakeDeposit,
44
+ poolDeposit: parameters.poolDeposit,
45
+ drepDeposit: parameters.drepDeposit,
46
+ govActionDeposit: parameters.governanceActionDeposit,
47
+ priceMem: 0,
48
+ priceStep: 0,
49
+ maxTxExMem: 0n,
50
+ maxTxExSteps: 0n,
51
+ coinsPerUtxoByte: parameters.coinsPerUtxoByte,
52
+ collateralPercentage: 0,
53
+ maxCollateralInputs: 0,
54
+ minFeeRefScriptCostPerByte: 0,
55
+ costModels: { PlutusV1: {}, PlutusV2: {}, PlutusV3: {} }
56
+ });
57
+ const assetsOf = (output) => (output.assets ?? []).reduce((assets, asset) => Assets.addByHex(assets, asset.policyId, asset.assetName, BigInt(asset.quantity)), Assets.fromLovelace(BigInt(output.lovelace)));
58
+ /**
59
+ * `Schema.decodeSync(FromBech32)` and not `DRep.fromBech32`: the SDK's
60
+ * declarations carry that function and the shipped module does not export it,
61
+ * so calling it compiles and throws. The seventh gap of ADR-0004.
62
+ */
63
+ const drepFromBech32 = Schema.decodeSync(DRep.FromBech32);
64
+ const drepOf = (declared) => {
65
+ if (declared.drep === "abstain")
66
+ return DRep.alwaysAbstain();
67
+ if (declared.drep === "noConfidence")
68
+ return DRep.alwaysNoConfidence();
69
+ return drepFromBech32(declared.drep);
70
+ };
71
+ /**
72
+ * The Conway forms throughout. The legacy pair encodes no deposit and no
73
+ * refund, and evolution-sdk's builder therefore leaves both out of the balance —
74
+ * a transaction the ledger rejects, because consumed and produced no longer
75
+ * agree. The stated deposit is the protocol parameter exactly, which is what
76
+ * the ledger charges and what the gate holds it to (ADR-0013).
77
+ */
78
+ const applyCertificate = (builder, declared, stakeCredential) => {
79
+ switch (declared.type) {
80
+ case "stakeRegistration":
81
+ return builder.registerStake({ stakeCredential });
82
+ case "stakeDeregistration":
83
+ return builder.deregisterStake({ stakeCredential });
84
+ case "stakeDelegation":
85
+ return builder.delegateToPool({ stakeCredential, poolKeyHash: PoolKeyHash.fromBech32(declared.poolId) });
86
+ case "voteDelegation":
87
+ return builder.delegateToDRep({ stakeCredential, drep: drepOf(declared) });
88
+ }
89
+ };
90
+ const actsOnStake = (intent) => (intent.certificates ?? []).length > 0 || intent.withdrawRewards === true;
91
+ /** The two sites evolution-sdk reports a shortfall from, neither of which carries a structured cause. */
92
+ const isShortfall = (message) => message.startsWith("Coin selection failed") || message.includes("Insufficient funds to cover");
93
+ const readFailure = (cause) => {
94
+ const message = cause instanceof Error ? cause.message : String(cause);
95
+ return isShortfall(message)
96
+ ? refuse("InsufficientFunds", "This wallet does not hold enough to cover the transaction and its fee.", cause)
97
+ : refuse("CannotBalance", `This intent could not be built into a transaction: ${message}`, cause);
98
+ };
99
+ /**
100
+ * Builds the transaction, or says why not. Nothing here asks the network
101
+ * anything, and nothing describing what the wallet holds leaves this function.
102
+ */
103
+ export const balanceIntent = (inputs) => Effect.gen(function* () {
104
+ const { changeAddress, intent, network, parameters, utxos } = inputs;
105
+ const validUntil = Date.parse(intent.validUntil);
106
+ if (validUntil <= inputs.now) {
107
+ return yield* Effect.fail(refuse("IntentExpired", "This request expired while it was open. Ask for a fresh one."));
108
+ }
109
+ for (const output of intent.outputs ?? []) {
110
+ if (!addressIsOnNetwork(output.address, network)) {
111
+ return yield* Effect.fail(refuse("ForeignAddress", `This Slip is on ${network} and it asks to pay an address on another network.`));
112
+ }
113
+ }
114
+ // Inside the error channel, not thrown past it: the signature promises a
115
+ // `BalanceError` and a defect here would reach a person as a stack trace.
116
+ const change = yield* Effect.try({
117
+ try: () => Address.fromBech32(changeAddress),
118
+ catch: (cause) => refuse("UnreadableChangeAddress", "This wallet's change address could not be read as an address.", cause)
119
+ });
120
+ const credential = change.stakingCredential;
121
+ if (actsOnStake(intent) && credential === undefined) {
122
+ return yield* Effect.fail(refuse("NoStakeCredential", "This action acts on a stake credential and this wallet's address carries none."));
123
+ }
124
+ if (intent.withdrawRewards === true && inputs.rewardBalance === undefined) {
125
+ return yield* Effect.fail(refuse("RewardBalanceUnknown", "The reward balance to withdraw is not known, so this cannot be built."));
126
+ }
127
+ const stake = credential === undefined
128
+ ? null
129
+ : {
130
+ credential,
131
+ certificates: intent.certificates ?? [],
132
+ withdrawal: intent.withdrawRewards === true ? (inputs.rewardBalance ?? 0n) : null
133
+ };
134
+ const built = yield* Effect.tryPromise({
135
+ try: async () => {
136
+ let builder = makeTxBuilder({ chain: chains[network] });
137
+ for (const output of intent.outputs ?? []) {
138
+ // Declared lovelace is a floor: `autoMinUtxo` raises an output that
139
+ // cannot pay for its own bytes, and the difference is shown to the
140
+ // person as the client's own adjustment rather than folded in.
141
+ builder = builder.payToAddress({ address: Address.fromBech32(output.address), assets: assetsOf(output) });
142
+ }
143
+ if (stake !== null) {
144
+ for (const declared of stake.certificates)
145
+ builder = applyCertificate(builder, declared, stake.credential);
146
+ if (stake.withdrawal !== null) {
147
+ builder = builder.withdraw({ stakeCredential: stake.credential, amount: stake.withdrawal });
148
+ }
149
+ }
150
+ // Never after `validUntil`, which is the whole of what the spec fixes here.
151
+ builder = builder.setValidity({ to: BigInt(validUntil) });
152
+ return await builder.build({
153
+ changeAddress: change,
154
+ availableUtxos: utxos,
155
+ protocolParameters: builderParameters(parameters),
156
+ fullProtocolParameters: depositParameters(parameters),
157
+ slotConfig: slotConfigOf(parameters),
158
+ autoMinUtxo: true,
159
+ // Leftover too small to become change would otherwise be paid as fee —
160
+ // lovelace leaving the wallet that nothing on screen accounted for.
161
+ onInsufficientChange: "error"
162
+ });
163
+ },
164
+ catch: readFailure
165
+ });
166
+ const transaction = yield* Effect.tryPromise({ try: () => built.toTransaction(), catch: readFailure });
167
+ const ttl = transaction.body.ttl;
168
+ if (ttl === undefined) {
169
+ // We asked for an interval; a body without one could be submitted after
170
+ // `validUntil`, which is the one thing the spec forbids outright here.
171
+ return yield* Effect.fail(refuse("CannotBalance", "The built transaction carries no expiry, and it must."));
172
+ }
173
+ return { cbor: Transaction.toCBORHex(transaction), fee: transaction.body.fee, ttl };
174
+ });
175
+ //# sourceMappingURL=balance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balance.js","sourceRoot":"","sources":["../src/balance.ts"],"names":[],"mappings":"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"}