@cardano-slips/flow 0.0.3 → 0.2.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 (84) hide show
  1. package/README.md +27 -0
  2. package/dist/address.d.ts +13 -0
  3. package/dist/address.d.ts.map +1 -0
  4. package/dist/address.js +54 -0
  5. package/dist/address.js.map +1 -0
  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/cip30.d.ts +76 -0
  15. package/dist/cip30.d.ts.map +1 -0
  16. package/dist/cip30.js +69 -0
  17. package/dist/cip30.js.map +1 -0
  18. package/dist/complete-error.d.ts +50 -0
  19. package/dist/complete-error.d.ts.map +1 -0
  20. package/dist/complete-error.js +47 -0
  21. package/dist/complete-error.js.map +1 -0
  22. package/dist/complete.d.ts +58 -0
  23. package/dist/complete.d.ts.map +1 -0
  24. package/dist/complete.js +108 -0
  25. package/dist/complete.js.map +1 -0
  26. package/dist/connect.d.ts +45 -0
  27. package/dist/connect.d.ts.map +1 -0
  28. package/dist/connect.js +73 -0
  29. package/dist/connect.js.map +1 -0
  30. package/dist/discovery.d.ts +37 -0
  31. package/dist/discovery.d.ts.map +1 -0
  32. package/dist/discovery.js +71 -0
  33. package/dist/discovery.js.map +1 -0
  34. package/dist/index.d.ts +27 -7
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +15 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/registry.d.ts +18 -0
  39. package/dist/registry.d.ts.map +1 -0
  40. package/dist/registry.js +15 -0
  41. package/dist/registry.js.map +1 -0
  42. package/dist/resolve.d.ts +11 -0
  43. package/dist/resolve.d.ts.map +1 -0
  44. package/dist/resolve.js +21 -0
  45. package/dist/resolve.js.map +1 -0
  46. package/dist/sign-error.d.ts +62 -0
  47. package/dist/sign-error.d.ts.map +1 -0
  48. package/dist/sign-error.js +42 -0
  49. package/dist/sign-error.js.map +1 -0
  50. package/dist/sign.d.ts +38 -0
  51. package/dist/sign.d.ts.map +1 -0
  52. package/dist/sign.js +79 -0
  53. package/dist/sign.js.map +1 -0
  54. package/dist/tokens.css +133 -0
  55. package/dist/utxo.d.ts +16 -0
  56. package/dist/utxo.d.ts.map +1 -0
  57. package/dist/utxo.js +51 -0
  58. package/dist/utxo.js.map +1 -0
  59. package/dist/wallet-error.d.ts +48 -0
  60. package/dist/wallet-error.d.ts.map +1 -0
  61. package/dist/wallet-error.js +31 -0
  62. package/dist/wallet-error.js.map +1 -0
  63. package/dist/witness.d.ts +23 -0
  64. package/dist/witness.d.ts.map +1 -0
  65. package/dist/witness.js +101 -0
  66. package/dist/witness.js.map +1 -0
  67. package/package.json +10 -5
  68. package/src/address.ts +69 -0
  69. package/src/balance-error.ts +77 -0
  70. package/src/balance.ts +285 -0
  71. package/src/cip30.ts +113 -0
  72. package/src/complete-error.ts +83 -0
  73. package/src/complete.ts +198 -0
  74. package/src/connect.ts +136 -0
  75. package/src/discovery.ts +92 -0
  76. package/src/index.ts +37 -7
  77. package/src/registry.ts +32 -0
  78. package/src/resolve.ts +40 -0
  79. package/src/sign-error.ts +89 -0
  80. package/src/sign.ts +118 -0
  81. package/src/tokens.css +133 -0
  82. package/src/utxo.ts +70 -0
  83. package/src/wallet-error.ts +68 -0
  84. package/src/witness.ts +132 -0
package/README.md CHANGED
@@ -30,6 +30,33 @@ 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
+ ## Tokens
34
+
35
+ ```ts
36
+ import "@cardano-slips/flow/tokens.css"
37
+ ```
38
+
39
+ ```html
40
+ <div class="slip-root">…</div>
41
+ <div class="slip-root" data-theme="dark">…</div>
42
+ ```
43
+
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.
45
+
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:
49
+
50
+ | Family | What it is |
51
+ | --- | --- |
52
+ | `--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 |
55
+
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.
57
+
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.
59
+
33
60
  ## Entry point
34
61
 
35
62
  One export, the package root. Deep imports into `dist/` are not a supported surface, so moving a file is never a breaking change:
@@ -0,0 +1,13 @@
1
+ import { Either } from "effect";
2
+ /** CIP-30's `getNetworkId`: 1 is mainnet, 0 is every test network. */
3
+ export type NetworkId = 0 | 1;
4
+ export type WalletAddress = {
5
+ readonly bech32: string;
6
+ readonly networkId: NetworkId;
7
+ };
8
+ /**
9
+ * Reads what CIP-30 returned. `Either` and not a throw: this runs on whatever a
10
+ * browser extension chose to send, and every refusal reaches a person as words.
11
+ */
12
+ export declare const readWalletAddress: (hex: string) => Either.Either<WalletAddress, string>;
13
+ //# sourceMappingURL=address.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * CIP-30 hands addresses back as hex; the endpoint is sent bech32, because that
3
+ * is what a `BuildRequest` carries and what a person can recognise. The
4
+ * conversion is also the second statement of network — the header byte says
5
+ * which chain the address is for, and a wallet whose `getNetworkId` disagrees
6
+ * with its own address has answered two ways.
7
+ */
8
+ import { PaymentAddress } from "@cardano-slips/core";
9
+ import { encodeBech32 } from "@cardano-slips/verifier";
10
+ import { Either, Schema } from "effect";
11
+ const decodePaymentAddress = Schema.decodeUnknownEither(PaymentAddress);
12
+ const refuse = (detail) => Either.left(detail);
13
+ const fromHex = (hex) => {
14
+ if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex))
15
+ return undefined;
16
+ const bytes = new Uint8Array(hex.length / 2);
17
+ for (let index = 0; index < bytes.length; index++)
18
+ bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
19
+ return bytes;
20
+ };
21
+ /**
22
+ * CIP-30 calls the value "the CBOR of the address" and wallets ship the address
23
+ * bytes bare. Both are accepted, and they cannot be confused: `0x58` as a first
24
+ * byte is a CBOR byte string of up to 255 bytes, and as an address header it
25
+ * would claim network 8, which does not exist.
26
+ */
27
+ const unwrapCbor = (bytes) => bytes.length > 2 && bytes[0] === 0x58 && bytes[1] === bytes.length - 2 ? bytes.subarray(2) : bytes;
28
+ /** CIP-19: the header's high nibble is the address type, the low nibble the network. Types 0-7 can hold a payment. */
29
+ const LAST_PAYMENT_TYPE = 7;
30
+ /**
31
+ * Reads what CIP-30 returned. `Either` and not a throw: this runs on whatever a
32
+ * browser extension chose to send, and every refusal reaches a person as words.
33
+ */
34
+ export const readWalletAddress = (hex) => {
35
+ const raw = fromHex(hex.trim());
36
+ if (raw === undefined)
37
+ return refuse(`${hex.slice(0, 16)}… is not hex`);
38
+ const bytes = unwrapCbor(raw);
39
+ const header = bytes[0];
40
+ const networkId = header & 0x0f;
41
+ if (networkId !== 0 && networkId !== 1)
42
+ return refuse(`the address header names network ${networkId}`);
43
+ const type = header >> 4;
44
+ if (type > LAST_PAYMENT_TYPE) {
45
+ // A reward address (14, 15) or a Byron address (8) cannot receive change.
46
+ return refuse(`address type ${type} cannot hold a payment`);
47
+ }
48
+ const bech32 = encodeBech32(networkId === 1 ? "addr" : "addr_test", bytes);
49
+ return Either.match(decodePaymentAddress(bech32), {
50
+ onLeft: () => refuse(`${bech32.slice(0, 16)}… is not a payment address`),
51
+ onRight: () => Either.right({ bech32, networkId: networkId })
52
+ });
53
+ };
54
+ //# sourceMappingURL=address.js.map
@@ -0,0 +1 @@
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":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,kBAAkB,EAA4D,MAAM,qBAAqB,CAAA;AAElH,OAAO,EACL,OAAO,EACP,MAAM,EACN,IAAI,EACJ,OAAO,EACP,WAAW,EACX,OAAO,EACP,OAAO,EACP,MAAM,EAEN,WAAW,EAEZ,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,aAAa,EAGd,MAAM,0DAA0D,CAAA;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAqB,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAuC9D,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,YAAY,GAAG,CAAC,EAAE,KAAK,EAAuB,EAAyB,EAAE,CAAC,CAAC;IAC/E,QAAQ,EAAE,KAAK,CAAC,IAAI;IACpB,QAAQ,EAAE,KAAK,CAAC,IAAI;IACpB,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;CACrC,CAAC,CAAA;AAEF,MAAM,iBAAiB,GAAG,CAAC,UAA+B,EAAqB,EAAE,CAAC,CAAC;IACjF,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;IAC/C,cAAc,EAAE,UAAU,CAAC,cAAc;IACzC,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;IAC7C,SAAS,EAAE,UAAU,CAAC,SAAS;CAChC,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,CAAC,UAA+B,EAAE,EAAE,CAAC,CAAC;IAC9D,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC;IAC1C,SAAS,EAAE,UAAU,CAAC,SAAS;IAC/B,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,UAAU,CAAC,YAAY;IACnC,WAAW,EAAE,UAAU,CAAC,WAAW;IACnC,WAAW,EAAE,UAAU,CAAC,WAAW;IACnC,gBAAgB,EAAE,UAAU,CAAC,uBAAuB;IACpD,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;IACZ,UAAU,EAAE,EAAE;IACd,YAAY,EAAE,EAAE;IAChB,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;IAC7C,oBAAoB,EAAE,CAAC;IACvB,mBAAmB,EAAE,CAAC;IACtB,0BAA0B,EAAE,CAAC;IAC7B,UAAU,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;CACzD,CAAC,CAAA;AAEF,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAiB,EAAE,CACjD,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAC1B,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EACnG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAC7C,CAAA;AAEH;;;;GAIG;AACH,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;AAEzD,MAAM,MAAM,GAAG,CAAC,QAA2D,EAAa,EAAE;IACxF,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,aAAa,EAAE,CAAA;IAC5D,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAA;IACtE,OAAO,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AACtC,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,gBAAgB,GAAG,CACvB,OAAmC,EACnC,QAAqB,EACrB,eAAgC,EACJ,EAAE;IAC9B,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,mBAAmB;YACtB,OAAO,OAAO,CAAC,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;QACnD,KAAK,qBAAqB;YACxB,OAAO,OAAO,CAAC,eAAe,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;QACrD,KAAK,iBAAiB;YACpB,OAAO,OAAO,CAAC,cAAc,CAAC,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAC1G,KAAK,gBAAgB;YACnB,OAAO,OAAO,CAAC,cAAc,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC9E,CAAC;AACH,CAAC,CAAA;AAiBD,MAAM,WAAW,GAAG,CAAC,MAAc,EAAW,EAAE,CAC9C,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,eAAe,KAAK,IAAI,CAAA;AAE3E,yGAAyG;AACzG,MAAM,WAAW,GAAG,CAAC,OAAe,EAAW,EAAE,CAC/C,OAAO,CAAC,UAAU,CAAC,uBAAuB,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CAAA;AAEhG,MAAM,WAAW,GAAG,CAAC,KAAc,EAAgB,EAAE;IACnD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,OAAO,WAAW,CAAC,OAAO,CAAC;QACzB,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,wEAAwE,EAAE,KAAK,CAAC;QAC9G,CAAC,CAAC,MAAM,CAAC,eAAe,EAAE,sDAAsD,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;AACrG,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAqB,EAAoD,EAAE,CACvG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,MAAM,CAAA;IAEpE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IAChD,IAAI,UAAU,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,8DAA8D,CAAC,CAAC,CAAA;IACpH,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;YACjD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,OAAO,oDAAoD,CAAC,CACzG,CAAA;QACH,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,0EAA0E;IAC1E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAC/B,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC;QAC5C,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,MAAM,CAAC,yBAAyB,EAAE,+DAA+D,EAAE,KAAK,CAAC;KAC5G,CAAC,CAAA;IACF,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAA;IAC3C,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QACpD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,MAAM,CAAC,mBAAmB,EAAE,gFAAgF,CAAC,CAC9G,CAAA;IACH,CAAC;IAED,IAAI,MAAM,CAAC,eAAe,KAAK,IAAI,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QAC1E,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,MAAM,CAAC,sBAAsB,EAAE,uEAAuE,CAAC,CACxG,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GACT,UAAU,KAAK,SAAS;QACtB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC;YACE,UAAU;YACV,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;YACvC,UAAU,EAAE,MAAM,CAAC,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI;SAClF,CAAA;IAEP,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QACrC,GAAG,EAAE,KAAK,IAAI,EAAE;YACd,IAAI,OAAO,GAA+B,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAEnF,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBAC1C,oEAAoE;gBACpE,mEAAmE;gBACnE,+DAA+D;gBAC/D,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YAC3G,CAAC;YAED,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,YAAY;oBAAE,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;gBAC1G,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;oBAC9B,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;gBAC7F,CAAC;YACH,CAAC;YAED,4EAA4E;YAC5E,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;YAEzD,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC;gBACzB,aAAa,EAAE,MAAM;gBACrB,cAAc,EAAE,KAAK;gBACrB,kBAAkB,EAAE,iBAAiB,CAAC,UAAU,CAAC;gBACjD,sBAAsB,EAAE,iBAAiB,CAAC,UAAU,CAAC;gBACrD,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC;gBACpC,WAAW,EAAE,IAAI;gBACjB,uEAAuE;gBACvE,oEAAoE;gBACpE,oBAAoB,EAAE,OAAO;aAC9B,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,EAAE,WAAW;KACnB,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;IAEtG,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAA;IAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,wEAAwE;QACxE,uEAAuE;QACvE,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,uDAAuD,CAAC,CAAC,CAAA;IAC7G,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAA;AACrF,CAAC,CAAC,CAAA"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The CIP-30 surface this client calls, declared here because evolution-sdk's
3
+ * `WalletApi` omits `getChangeAddress`, `getCollateral` and `getNetworkId`
4
+ * while the object a wallet actually hands back carries all three (ADR-0004).
5
+ * A typing we assert rather than one the SDK guarantees, so it is proved
6
+ * against a stubbed provider rather than trusted.
7
+ */
8
+ /** Hex-encoded CBOR: the only form CIP-30 speaks, and the form `verifier` decodes. */
9
+ export type CborHex = string;
10
+ export type Paginate = {
11
+ readonly page: number;
12
+ readonly limit: number;
13
+ };
14
+ export type SignedData = {
15
+ readonly signature: CborHex;
16
+ readonly key: CborHex;
17
+ };
18
+ export interface Cip30Api {
19
+ readonly getNetworkId: () => Promise<number>;
20
+ readonly getChangeAddress: () => Promise<CborHex>;
21
+ readonly getUsedAddresses: (paginate?: Paginate) => Promise<ReadonlyArray<CborHex>>;
22
+ readonly getUnusedAddresses: () => Promise<ReadonlyArray<CborHex>>;
23
+ readonly getRewardAddresses: () => Promise<ReadonlyArray<CborHex>>;
24
+ readonly getBalance: () => Promise<CborHex>;
25
+ /** `null` where the wallet has nothing to give, per CIP-30. */
26
+ readonly getUtxos: (amount?: CborHex, paginate?: Paginate) => Promise<ReadonlyArray<CborHex> | null>;
27
+ readonly getCollateral: (params?: {
28
+ readonly amount: CborHex;
29
+ }) => Promise<ReadonlyArray<CborHex> | null>;
30
+ /** Returns a **witness set**, never a signed transaction — invariant 4 is CIP-30's own shape. */
31
+ readonly signTx: (tx: CborHex, partialSign?: boolean) => Promise<CborHex>;
32
+ readonly signData: (address: CborHex, payload: CborHex) => Promise<SignedData>;
33
+ readonly submitTx: (tx: CborHex) => Promise<string>;
34
+ }
35
+ /** What an extension injects at `window.cardano[key]`, before anyone calls `enable()`. */
36
+ export interface Cip30Provider {
37
+ readonly apiVersion: string;
38
+ readonly name: string;
39
+ readonly icon: string;
40
+ readonly supportedExtensions?: ReadonlyArray<{
41
+ readonly cip: number;
42
+ }>;
43
+ readonly enable: (extensions?: ReadonlyArray<{
44
+ readonly cip: number;
45
+ }>) => Promise<Cip30Api>;
46
+ readonly isEnabled: () => Promise<boolean>;
47
+ }
48
+ /**
49
+ * Shape, not name: `window.cardano` is a namespace anything may write to, and a
50
+ * key that does not answer these four is not a connector whatever it is called.
51
+ */
52
+ export declare const isCip30Provider: (value: unknown) => value is Cip30Provider;
53
+ export declare const isCip30Api: (value: unknown) => value is Cip30Api;
54
+ /** CIP-30's `APIError`, kept whole: the numeric code is what says a person declined. */
55
+ export type Cip30ApiError = {
56
+ readonly code: number;
57
+ readonly info: string;
58
+ };
59
+ /** The four `APIError` codes CIP-30 defines. Anything else is passed through as its number. */
60
+ export declare const apiErrorNames: Readonly<Record<number, string>>;
61
+ /** `-3` is the person saying no, which is not a fault and must not be shown as one. */
62
+ export declare const REFUSED = -3;
63
+ /**
64
+ * `TxSignError` and `TxSendError` are `APIError`'s shape on their own
65
+ * numbering, and the numbering is the footgun: a declined signature is `2`
66
+ * here, where `2` in `APIError` is an internal error. They never share a call,
67
+ * so which table applies is decided by the method that rejected.
68
+ */
69
+ export declare const txSignErrorNames: Readonly<Record<number, string>>;
70
+ /** `2` from `signTx`: the person declined in the wallet. */
71
+ export declare const USER_DECLINED = 2;
72
+ export declare const txSendErrorNames: Readonly<Record<number, string>>;
73
+ /** A wallet rejects with a plain `{ code, info }` object, not an `Error`. */
74
+ export declare const readApiError: (cause: unknown) => Cip30ApiError | undefined;
75
+ export declare const describeApiError: (error: Cip30ApiError) => string;
76
+ //# sourceMappingURL=cip30.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cip30.d.ts","sourceRoot":"","sources":["../src/cip30.ts"],"names":[],"mappings":"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"}
package/dist/cip30.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The CIP-30 surface this client calls, declared here because evolution-sdk's
3
+ * `WalletApi` omits `getChangeAddress`, `getCollateral` and `getNetworkId`
4
+ * while the object a wallet actually hands back carries all three (ADR-0004).
5
+ * A typing we assert rather than one the SDK guarantees, so it is proved
6
+ * against a stubbed provider rather than trusted.
7
+ */
8
+ const isFunction = (value) => typeof value === "function";
9
+ /**
10
+ * Shape, not name: `window.cardano` is a namespace anything may write to, and a
11
+ * key that does not answer these four is not a connector whatever it is called.
12
+ */
13
+ export const isCip30Provider = (value) => {
14
+ if (typeof value !== "object" || value === null)
15
+ return false;
16
+ const candidate = value;
17
+ return (isFunction(candidate.enable) &&
18
+ isFunction(candidate.isEnabled) &&
19
+ typeof candidate.name === "string" &&
20
+ typeof candidate.apiVersion === "string");
21
+ };
22
+ /** The methods we call. A provider may enable and still not answer them. */
23
+ const apiMethods = ["getNetworkId", "getChangeAddress", "getUsedAddresses", "getUtxos", "signTx", "submitTx"];
24
+ export const isCip30Api = (value) => {
25
+ if (typeof value !== "object" || value === null)
26
+ return false;
27
+ const candidate = value;
28
+ return apiMethods.every((method) => isFunction(candidate[method]));
29
+ };
30
+ /** The four `APIError` codes CIP-30 defines. Anything else is passed through as its number. */
31
+ export const apiErrorNames = {
32
+ [-1]: "InvalidRequest",
33
+ [-2]: "InternalError",
34
+ [-3]: "Refused",
35
+ [-4]: "AccountChange"
36
+ };
37
+ /** `-3` is the person saying no, which is not a fault and must not be shown as one. */
38
+ export const REFUSED = -3;
39
+ /**
40
+ * `TxSignError` and `TxSendError` are `APIError`'s shape on their own
41
+ * numbering, and the numbering is the footgun: a declined signature is `2`
42
+ * here, where `2` in `APIError` is an internal error. They never share a call,
43
+ * so which table applies is decided by the method that rejected.
44
+ */
45
+ export const txSignErrorNames = {
46
+ 1: "ProofGeneration",
47
+ 2: "UserDeclined"
48
+ };
49
+ /** `2` from `signTx`: the person declined in the wallet. */
50
+ export const USER_DECLINED = 2;
51
+ export const txSendErrorNames = {
52
+ 1: "Refused",
53
+ 2: "Failure"
54
+ };
55
+ /** A wallet rejects with a plain `{ code, info }` object, not an `Error`. */
56
+ export const readApiError = (cause) => {
57
+ if (typeof cause !== "object" || cause === null)
58
+ return undefined;
59
+ const candidate = cause;
60
+ if (typeof candidate.code !== "number")
61
+ return undefined;
62
+ return { code: candidate.code, info: typeof candidate.info === "string" ? candidate.info : "" };
63
+ };
64
+ export const describeApiError = (error) => {
65
+ const name = apiErrorNames[error.code];
66
+ const label = name === undefined ? `code ${error.code}` : name;
67
+ return error.info === "" ? label : `${label}: ${error.info}`;
68
+ };
69
+ //# sourceMappingURL=cip30.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cip30.js","sourceRoot":"","sources":["../src/cip30.ts"],"names":[],"mappings":"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"}