@helios-lang/effect 0.1.2 → 0.1.4

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 (50) hide show
  1. package/dist/Ledger/Address.js +14 -12
  2. package/dist/Ledger/Address.js.map +1 -1
  3. package/dist/Ledger/AssetClass.js +69 -0
  4. package/dist/Ledger/AssetClass.js.map +1 -0
  5. package/dist/Ledger/Assets.js +120 -0
  6. package/dist/Ledger/Assets.js.map +1 -0
  7. package/dist/Ledger/Credential.js +1 -1
  8. package/dist/Ledger/Credential.js.map +1 -1
  9. package/dist/Ledger/DatumHash.js +21 -0
  10. package/dist/Ledger/DatumHash.js.map +1 -0
  11. package/dist/Ledger/IsMainnet.js +4 -0
  12. package/dist/Ledger/IsMainnet.js.map +1 -0
  13. package/dist/Ledger/MintingPolicy.js +45 -0
  14. package/dist/Ledger/MintingPolicy.js.map +1 -0
  15. package/dist/Ledger/PubKeyHash.js +2 -2
  16. package/dist/Ledger/PubKeyHash.js.map +1 -1
  17. package/dist/Ledger/TxId.js +15 -0
  18. package/dist/Ledger/TxId.js.map +1 -0
  19. package/dist/Ledger/TxInput.js +51 -0
  20. package/dist/Ledger/TxInput.js.map +1 -0
  21. package/dist/Ledger/TxOutput.js +119 -0
  22. package/dist/Ledger/TxOutput.js.map +1 -0
  23. package/dist/Ledger/TxOutputDatum.js +41 -0
  24. package/dist/Ledger/TxOutputDatum.js.map +1 -0
  25. package/dist/Ledger/TxOutputId.js +39 -0
  26. package/dist/Ledger/TxOutputId.js.map +1 -0
  27. package/dist/Ledger/ValidatorHash.js +2 -2
  28. package/dist/Ledger/ValidatorHash.js.map +1 -1
  29. package/dist/Ledger/index.js +10 -0
  30. package/dist/Ledger/index.js.map +1 -1
  31. package/dist/Uplc/Data.js +24 -4
  32. package/dist/Uplc/Data.js.map +1 -1
  33. package/package.json +2 -1
  34. package/src/Ledger/Address.ts +27 -17
  35. package/src/Ledger/AssetClass.ts +90 -0
  36. package/src/Ledger/Assets.ts +164 -0
  37. package/src/Ledger/Credential.ts +1 -1
  38. package/src/Ledger/DatumHash.ts +36 -0
  39. package/src/Ledger/IsMainnet.ts +6 -0
  40. package/src/Ledger/MintingPolicy.ts +57 -0
  41. package/src/Ledger/PubKeyHash.ts +2 -2
  42. package/src/Ledger/TxId.ts +31 -0
  43. package/src/Ledger/TxInput.test.ts +21 -0
  44. package/src/Ledger/TxInput.ts +66 -0
  45. package/src/Ledger/TxOutput.ts +166 -0
  46. package/src/Ledger/TxOutputDatum.ts +64 -0
  47. package/src/Ledger/TxOutputId.ts +63 -0
  48. package/src/Ledger/ValidatorHash.ts +1 -1
  49. package/src/Ledger/index.ts +10 -0
  50. package/src/Uplc/Data.ts +28 -1
@@ -0,0 +1,164 @@
1
+ import { Effect, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import * as Cbor from "../Cbor.js"
4
+ import { Data } from "../Uplc"
5
+ import * as AssetClass from "./AssetClass.js"
6
+ import * as MintingPolicy from "./MintingPolicy.js"
7
+
8
+ export const Assets = Schema.Record({
9
+ key: Schema.String, // can sadly not use AssetClass.AssetClass here
10
+ value: Schema.BigIntFromSelf
11
+ }).pipe(
12
+ Schema.filter((assets) => {
13
+ for (const key in assets) {
14
+ if (!AssetClass.isValid(key)) {
15
+ return `Invalid AssetClass ${key}`
16
+ }
17
+ }
18
+
19
+ return true
20
+ })
21
+ )
22
+
23
+ export type Assets = Schema.Schema.Type<typeof Assets>
24
+
25
+ export const FromUplcData = Schema.transform(
26
+ Data.PairArray(
27
+ MintingPolicy.FromUplcData,
28
+ Data.PairArray(Data.Hex, Data.BigInt)
29
+ ),
30
+ Assets,
31
+ {
32
+ strict: true,
33
+ decode: (outer) => {
34
+ const assets: Record<string, bigint> = {}
35
+
36
+ for (const [policy, inner] of outer) {
37
+ for (const [tokenName, quantity] of inner) {
38
+ assets[AssetClass.make(policy, tokenName)] = quantity
39
+ }
40
+ }
41
+
42
+ return assets as Assets
43
+ },
44
+ encode: (assets) => {
45
+ const outer = nestedRecords(assets)
46
+
47
+ return Object.entries(outer).map(
48
+ ([policy, inner]) =>
49
+ [
50
+ Effect.runSync(MintingPolicy.make(policy)),
51
+ Object.entries(inner)
52
+ ] as const
53
+ )
54
+ }
55
+ }
56
+ )
57
+
58
+ function nestedRecords(assets: Assets): Record<string, Record<string, bigint>> {
59
+ const outer: Record<string, Record<string, bigint>> = {}
60
+
61
+ Object.entries(assets).forEach(([assetClass, quantity]) => {
62
+ if (assetClass.length == 0) {
63
+ outer[assetClass] = { "": quantity }
64
+ } else {
65
+ const policy = assetClass.slice(0, 56)
66
+ const tokenName = assetClass.slice(56)
67
+
68
+ if (policy in outer) {
69
+ outer[policy] = {
70
+ ...outer[policy],
71
+ [tokenName]: quantity
72
+ }
73
+ } else {
74
+ outer[policy] = {
75
+ [tokenName]: quantity
76
+ }
77
+ }
78
+ }
79
+ })
80
+
81
+ return outer
82
+ }
83
+
84
+ export const decode = (bytes: Bytes.BytesLike): Cbor.DecodeEffect<Assets> =>
85
+ Effect.gen(function* () {
86
+ const stream = Bytes.makeStream(bytes)
87
+
88
+ if (yield* Cbor.isTuple(bytes)) {
89
+ const [lovelace, otherAssets] = yield* Cbor.decodeTuple([
90
+ Cbor.decodeInt,
91
+ Cbor.decodeMap(
92
+ MintingPolicy.decode,
93
+ Cbor.decodeMap(Cbor.decodeBytes, Cbor.decodeInt)
94
+ )
95
+ ])(stream)
96
+
97
+ const assets: Record<string, bigint> = {}
98
+
99
+ if (lovelace != 0n) {
100
+ assets[AssetClass.ADA] = lovelace
101
+ }
102
+
103
+ for (const [policy, inner] of otherAssets) {
104
+ if (policy._tag == "None") {
105
+ return yield* new Cbor.DecodeError(
106
+ stream,
107
+ "unexpected ADA assetclass in encoded non-ADA assets"
108
+ )
109
+ }
110
+
111
+ for (const [tokenName, quantity] of inner) {
112
+ const assetClass = AssetClass.make(policy, tokenName)
113
+
114
+ assets[assetClass] = quantity
115
+ }
116
+ }
117
+
118
+ return assets as Assets
119
+ } else {
120
+ return { [AssetClass.ADA]: yield* Cbor.decodeInt(stream) }
121
+ }
122
+ })
123
+
124
+ export function encode(assets: Assets): number[] {
125
+ const acs = nonAdaAssetClasses(assets)
126
+
127
+ if (acs.length == 0) {
128
+ return Cbor.encodeInt(lovelace(assets))
129
+ } else {
130
+ const obj = nestedRecords(assets)
131
+ if (AssetClass.ADA in obj) {
132
+ delete obj[AssetClass.ADA]
133
+ }
134
+
135
+ return Cbor.encodeTuple([
136
+ Cbor.encodeInt(lovelace(assets)),
137
+ Cbor.encodeMap(
138
+ Object.entries(obj).map(([mph, tokens]) => {
139
+ return [
140
+ Cbor.encodeBytes(mph),
141
+ Cbor.encodeMap(
142
+ Object.entries(tokens).map(([tokenName, qty]) => [
143
+ Cbor.encodeBytes(tokenName),
144
+ Cbor.encodeInt(qty)
145
+ ])
146
+ )
147
+ ]
148
+ })
149
+ )
150
+ ])
151
+ }
152
+ }
153
+
154
+ export function allAssetClasses(assets: Assets): AssetClass.AssetClass[] {
155
+ return Object.keys(assets) as AssetClass.AssetClass[]
156
+ }
157
+
158
+ export function nonAdaAssetClasses(assets: Assets): AssetClass.AssetClass[] {
159
+ return allAssetClasses(assets).filter((ac) => ac != AssetClass.ADA)
160
+ }
161
+
162
+ export function lovelace(assets: Assets): bigint {
163
+ return assets[AssetClass.ADA] ?? 0n
164
+ }
@@ -1,7 +1,7 @@
1
1
  import { Schema } from "effect"
2
+ import { Data } from "../Uplc"
2
3
  import { PubKeyHash } from "./PubKeyHash.js"
3
4
  import { ValidatorHash } from "./ValidatorHash.js"
4
- import { Data } from "../Uplc/index.js"
5
5
 
6
6
  export const Credential = Schema.Union(
7
7
  Schema.TaggedStruct("PubKey", { hash: PubKeyHash }),
@@ -0,0 +1,36 @@
1
+ import { Effect, Encoding, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import { decodeBytes, DecodeEffect, encodeBytes } from "../Cbor.js"
4
+ import { Data } from "../Uplc"
5
+
6
+ export function isValid(dh: string): boolean {
7
+ return /^[0-9a-fA-F]+$/.test(dh) && dh.length == 64
8
+ }
9
+
10
+ export const DatumHash = Schema.String.pipe(
11
+ Schema.filter((dh: string) => isValid(dh) || "Invalid Cardano DatumHash"),
12
+ Schema.brand("DatumHash")
13
+ )
14
+
15
+ export type DatumHash = Schema.Schema.Type<typeof DatumHash>
16
+
17
+ export function make(bytes: Bytes.BytesLike) {
18
+ return Schema.decode(DatumHash)(Bytes.toHex(bytes))
19
+ }
20
+
21
+ export const FromUplcData = Schema.transform(Data.ByteArray, DatumHash, {
22
+ strict: true,
23
+ decode: Encoding.encodeHex,
24
+ encode: Bytes.toUint8Array
25
+ })
26
+
27
+ export const decode = (bytes: Bytes.BytesLike): DecodeEffect<DatumHash> =>
28
+ decodeBytes(bytes).pipe(
29
+ Effect.map((bytes) => new Uint8Array(bytes)),
30
+ Effect.map(Encoding.encodeHex),
31
+ Effect.map(Schema.decodeSync(DatumHash))
32
+ )
33
+
34
+ export function encode(dh: DatumHash): number[] {
35
+ return encodeBytes(dh)
36
+ }
@@ -0,0 +1,6 @@
1
+ import { Context } from "effect"
2
+
3
+ export class IsMainnet extends Context.Tag("IS_MAINNET")<
4
+ IsMainnet,
5
+ boolean
6
+ >() {}
@@ -0,0 +1,57 @@
1
+ import { Effect, Encoding, Option, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import * as Cbor from "../Cbor.js"
4
+ import { Data } from "../Uplc"
5
+ import * as ValidatorHash from "./ValidatorHash.js"
6
+
7
+ // None is used for ADA
8
+ export const MintingPolicy = Schema.Option(ValidatorHash.ValidatorHash)
9
+
10
+ export type MintingPolicy = Schema.Schema.Type<typeof MintingPolicy>
11
+
12
+ export const FromUplcData = Schema.transform(Data.ByteArray, MintingPolicy, {
13
+ strict: true,
14
+ decode: (bs) => {
15
+ if (bs.length == 0) {
16
+ return Option.none()
17
+ } else {
18
+ return Option.some(Encoding.encodeHex(bs))
19
+ }
20
+ },
21
+ encode: (opt) => {
22
+ if (opt._tag == "None") {
23
+ return new Uint8Array()
24
+ } else {
25
+ return Effect.runSync(Encoding.decodeHex(opt.value))
26
+ }
27
+ }
28
+ })
29
+
30
+ export function make(policy: Bytes.BytesLike) {
31
+ const p = Bytes.toHex(policy)
32
+
33
+ if (p.length == 0) {
34
+ return Effect.succeed(Option.none())
35
+ } else {
36
+ return ValidatorHash.make(p).pipe(Effect.map(Option.some))
37
+ }
38
+ }
39
+
40
+ export const decode = (
41
+ bytes: Bytes.BytesLike
42
+ ): Cbor.DecodeEffect<MintingPolicy> =>
43
+ Cbor.decodeBytes(bytes).pipe(
44
+ Effect.flatMap(make),
45
+ Effect.catchTag(
46
+ "ParseError",
47
+ (e) => new Cbor.DecodeError(Bytes.makeStream(bytes), e.message)
48
+ )
49
+ )
50
+
51
+ export function encode(policy: MintingPolicy): number[] {
52
+ if (policy._tag == "None") {
53
+ return Cbor.encodeBytes([])
54
+ } else {
55
+ return Cbor.encodeBytes(policy.value)
56
+ }
57
+ }
@@ -1,9 +1,9 @@
1
1
  import { Effect, Encoding, Schema } from "effect"
2
2
  import * as Bytes from "../internal/Bytes.js"
3
3
  import { decodeBytes, DecodeEffect, encodeBytes } from "../Cbor.js"
4
- import { Data } from "../Uplc/index.js"
4
+ import { Data } from "../Uplc"
5
5
 
6
- export function isValid(pkh: string): boolean {
6
+ export function isValid(pkh: string): pkh is PubKeyHash {
7
7
  return /^[0-9a-fA-F]+$/.test(pkh) && pkh.length == 56
8
8
  }
9
9
 
@@ -0,0 +1,31 @@
1
+ import { Effect, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import * as Cbor from "../Cbor.js"
4
+
5
+ export function isValid(txId: string): txId is TxId {
6
+ return txId.length == 64 && /^[0-9a-fA-F]+$/.test(txId)
7
+ }
8
+
9
+ export const TxId = Schema.String.pipe(
10
+ Schema.filter((id: string) => isValid(id) || "Invalid Cardano TxId"),
11
+ Schema.brand("TxId")
12
+ )
13
+
14
+ export type TxId = Schema.Schema.Type<typeof TxId>
15
+
16
+ export function make(txId: Bytes.BytesLike) {
17
+ return Schema.decode(TxId)(Bytes.toHex(txId))
18
+ }
19
+
20
+ export const decode = (bytes: Bytes.BytesLike): Cbor.DecodeEffect<TxId> =>
21
+ Cbor.decodeBytes(bytes).pipe(
22
+ Effect.flatMap(make),
23
+ Effect.catchTag(
24
+ "ParseError",
25
+ (e) => new Cbor.DecodeError(Bytes.makeStream(bytes), e.message)
26
+ )
27
+ )
28
+
29
+ export function encode(txId: TxId): number[] {
30
+ return Cbor.encodeBytes(txId)
31
+ }
@@ -0,0 +1,21 @@
1
+ import { describe, it } from "bun:test"
2
+ import { Effect } from "effect"
3
+ import { decode } from "./TxInput.js"
4
+
5
+ describe("TxInput.decode()", () => {
6
+ it("works for UTxO returned from Cip30 wallet", () => {
7
+ Effect.runSync(
8
+ decode(
9
+ "828258204cb4e9f79554fb3b572b19f68c8cce0dba929fcee2f6ab6cc390419a8d703bd8181882581d604988cad9aa1ebd733b165695cfef965fda2ee42dab2d8584c43b039c1a49da0141"
10
+ )
11
+ )
12
+ })
13
+
14
+ it("works for UTXO with V3 ref script", () => {
15
+ Effect.runSync(
16
+ decode(
17
+ "828258203d308c0f3deb1eff764cbb765452c53d30704748681d7acd61c7775aeb8a8e4600a4011a01393d92028201d8185853d8799f581c3babcffc6102ec25ced40e1a24fba20371925c46f0299b2b9456360ed8799f581cdb0d968cda2cc636b28c0f377e66691a065b8004e57be5129aeef8224461757468ff1a000f42401832183205ff03d818591174820259116f59116c010100333333323232323232323223222322322322322533300d3232323232533233013300130143754004264664464646464a66603460060022a66603a60386ea80280085854ccc068c02000454ccc074c070dd50050010b0a99980d18020008a99980e980e1baa00a0021616301a37540122646464646464646464a666042601460446ea80304c8c8c8c8c8c8c8c94ccc0a4c048c0a8dd50008991919191919191919191929919981a980f00409919299981d181e80109919191919299981e1813181e9baa001132533303d302b303e375400826601600226464646464a66608a60900042646464646464a666090606c60926ea8c134c138c128dd518268030a999824181918249baa00213253330493037304a37540042a666092606460946ea80044c8c8c8c8c8c8c8c8c8c94ccc158c1640084c8c8c8c8c8c8c8c8c8c8c8c8c94ccc18008454ccc18008c54ccc18000c54ccc18000840045280a5014a02940cdd79ba6041374c666605c666605c666062076022900101d807a40040ba9101044655454c0005432533333306600114a02646464a646660cc0042a6660c6600200a266e25200000314a026644a6660ca66ebcc19800930101400015333065337126eb4c19cc1a8dd59833801002898019ba600114a02a6660ca66e2520000051300300714a060d000460d20046ebcc19cc1a000cdd5801992999830982518311baa0011375a60c660cc6eacc198c18cdd50008a400060ca0026466600200203844660cc004660cc6e980052f5c0444a6660ca00426600298103d87a80004bd6f7b630099199911299983319b9148900003153330663371e91010000313300530403306a374c00497ae00011330054c103d87a8000006133300700700122330070023306c337606ea4014dd30020009bae3064001375660ca00260d200660ce00429405280a50374c666605a666060074020900102e245044655454c00053533305d337120a86466e00c004050c00404894ccc178cdc4000a40002605400220022a6660ba0062a6660ba004200229405280a5032533305d304b305e3754002266e24dd69831182f9baa00100b163037305e3754606060bc6ea80f4cdc780599b8a48810550494c4f54003730600407066e3c030cdc52450453484950003730600206e46e64cc008dd4000a450030010012225333233330620031323232323300a0013371491101280053330620021337149101035b5d2900006133714911035b5f2000333300900233714911025d29000062233300a00a00230070012233300a00a002001533305e337100049007099b80483c80400854ccc178cdc40012410004266e00cdc0241002800490068b1bac305f002375a60ba0026466ec0dd4182e8009ba7305e0013754006264a6660be002266e292201027b7d00003133714911037b5f20003232330010010032253330620011003132533306300113233300a00a3062001337149101023a200033300a00a3063001005306500213233300a00a3062001337149101023a200033300a00a30630013007330040040023065002306500133714910102207d000033756006264a6660be002266e29221025b5d00003133714911035b5f2000333300600133714911015d000032233300700700230040012233300700700200137580066e292201022c2000133005375a00400226466e2922010268270032333001001337006e340092001337149101012700003222533305e3371000490000800899191919980300319b8000548004cdc599b80002533306133710004900a0a40c02903719b8b33700002a6660c266e2000520141481805206e0043370c004901019b8300148080cdc70020011bae0022222323300100100522533305f00110051325333060001133004306200200613300530620023300300300130620012232330010010032253330593042001133714910101300000315333059337100029000099b8a489012d0033002002302500113300533708002900a19b8b3370066e1400520144818000cc0040048894ccc158cdc4801240002002266600600666e1000920143371666e00cdc28012402890300008b1bad30570013057002375c60aa00260aa0046eb8c14c004c14c008dd6982880098288011bad304f001304b37540022c2c609a60946ea80085858c130c134008c12c004c12c008dd59824800982480098221baa0011630460013300d0232325333042303030433754002266e3c078dd7182398221baa00114a0603860866ea8c070c10cdd5000a99981f99baf374c00a6e98cccc038dd5980998209baa30133041375402c9110048810003a100114a066e212000333013004375c603260806ea80ecdd7180918201baa03b3375e602e660826ea0cdc000d24004660826ea40652f5c00022c6082607c6ea800458c10000cdd5981f801981f181f800981f000981e981c9baa00116303b0013300201823375e602260706ea8004c044c0e0dd51805181c1baa00d15333035302300813232533303a303d00213232323232533303c3026303d3754002264a66607a6056607c6ea80104c8c8c8c8c94ccc114c1200084c8c8c8c8c94ccc11cc0c4c120dd50008992999824181b18249baa00413232533304a3033304b3754006264646464646464646464a6660ae60b40042646464a6660ae0342a6660ae0322a6660ae0302a6660ae01e2a6660ae01c2a6660ae0062a6660ae004200229405280a5014a029405280a503375e6e980e0dd31999812999814019003a40020a89101044655454c00302233302b0110544881044655454c00325333056304430573754002266e2400cdd6982d982c1baa00116303030573754606060ae6ea80d8cdd79ba7330583750012660b06ea001d2f5c0981049f0000ff0016375a60b000260b00046eb8c158004c158008dd7182a000982a0011bad30520013052002375a60a000260986ea800c58cdd79ba732323300100102b22533304f00114bd70099199911299982819baf00700313305400233006006001133006006001304e001304f001305300230510013374a900119826981218259baa0084bd701ba73304d4c0103d87b80004bd70191929998269828001099299982599b88371a00400229404cdc7999b8c480000040092201045348495000371a910104534849500016375c609c002646600200264a666094607060966ea800452f5bded8c026eacc13cc130dd50009980f8020129129998268008a5eb804cc138c12cc13c004cc008008c14000458c130c124dd50008b18258019bab304a0033049304a0013049001304830443754602c60886ea800458c118004cc0340908c8c8c94ccc110c0c8c114dd50008a999822181918229baa3049304a00213371e6eb8c124c118dd5000810001801982400098221baa301d30443754602c60886ea80085281919baf374c600200c6e98c004dd5980a18211baa30143042375402e4646600200200444a66608a002297adef6c60132333222533304633722910100003153330463371e9101000031001100513304a337606ea400cdd3001198030030009bae30440013756608a0026092004608e00264646464a666084605660866ea80044c8c8c8cdc499b82375a60940026eb4c128c12c008cdc11bad304a002375a60946096002608c6ea8c8c8c080cc128dd419b82375a60960046eb4c12c004cc128dd419b82375a609660980046eb4c12cc1300052f5c0608e6ea8c8c8c8c8c08ccc134dd419b81337046eb4c138010004cdc11bad304e0020033304d375066e0800c0052f5c06eb4c134c138004c124dd5182618249baa006375a60966098002608e6ea8c00d200230463754600400a608a6ea8c00400c8c074cc11cdd400099823a610101004bd700b2999820a5014c0103d87a8000153330414a0260366608a60366608a6ea0c0340e8cc1153001023863004bd7025eb804c06ccc114c06ccc114dd401d19822a61021864004bd7025eb80c008018c004dd5980998209baa30133041375402c46660280029101004881003300b00113375e0380022c6082607c6ea800458c10000cdd5981f801981f181f800981f000981e981c9baa00116303b0013300201823375e602260706ea8004c044c0e0dd51805181c1baa00d15333035301e303637546601c0324a66606c66606ca66606c603e606e6ea8c044c0e0dd51808981c1baa300a303837540022940528a504a2266e21200033300b3756601460706ea8c028c0e0dd50009bae3011303837540666eb8c028c0e0dd50198a5014a22940dc0a400044646600200200644a666074002297ae0133225333039300500213303d00233004004001133004004001303c001303d001225333034301d30353754004264646464a666076607c00400a2c6eb8c0f0004c0f0008dd6981d000981b1baa0021622225333035301e0011004132323300100100622533303b00113303c337606ea4018dd3001a5eb7bdb1804c8ccc8894ccc0f0cdc800500189982019bb037520146e9801c01454ccc0f0cdc7805001899299981e9813181f1baa001133041337606ea402cc108c0fcdd5000801080119299981ea9998200008a5114a02980103d87a80001301733041374c00297ae03233001001003225333041001133042337606ea402cdd400525eb7bdb1804c8ccc8894ccc108cdc800780189982319bb0375201e6ea003801454ccc108cdc78078018992999821981618221baa001133047337606ea4040c120c114dd5000801080119299982198160008a6103d87a80001301d33047375000297ae03370000401c26608c66ec0dd48019ba800233006006001375c60800026eb4c104004c114008c10c0044cc100cdd81ba9003374c0046600c00c0026eb8c0e8004dd5981d800981f801181e800991900118030009981c99bb037520046ea00052f5bded8c0600200244a666068002293099299981a8008a4c264666444a66606c66e4000c0084cc01c01ccc0e801000458dd7181a181c0019bae30340013039002303700130370012225333031301a00114bd6f7b6300991919800800a5eb7bdb180894ccc0dc0044cc0e0cdd81ba9006374c00697adef6c6013233322253330383372001400626607866ec0dd48051ba6007005153330383371e01400626607866ec0dd48051ba600700113303c337606ea400cdd3001198030030009bae30360013756606e00260760046072002646600200297adef6c60225333036001133037337606ea4010dd4001a5eb7bdb1804c8ccc8894ccc0dccdc800400189981d99bb037520106ea001c01454ccc0dccdc780400189981d99bb037520106ea001c0044cc0eccdd81ba900337500046600c00c0026eb8c0d4004dd6981b000981d001181c00098171baa01d23032303300122232533302f301d303037540022900009bad30343031375400264a66605e603a60606ea80045300103d87a8000132330010013756606a60646ea8008894ccc0d0004530103d87a80001323332225333035337220100062a66606a66e3c02000c4c03ccc0e4dd400125eb80530103d87a8000133006006001375c60660026eb4c0d0004c0e0008c0d8004cc01000c00888c8cc00400400c894ccc0c4004530103d87a800013233322253330323372200e0062a66606466e3c01c00c4c030cc0d8dd300125eb80530103d87a8000133006006001375c60600026eacc0c4004c0d4008c0cc004c0b8c0acdd50008b19800806119baf3004302b375400202a44646600200200644a66605c0022980103d87a800013322533302d300500213007330310024bd70099802002000981800098188009ba5480008c0ac004dd7181498150011bad302800130243754002604c60466ea803058dd598129813181300298120021bab3023004375860440086eb0c084010c084c084c084004c080c080004c07cc07c004c068dd50049b8748000dc3a4008603200260326034002602a6ea8008dc3a40042c602c602e006602a00460280046028002601e6ea800452613656375a0026eb4004dd68009bad001375c002ae6955ceaab9e5573eae815d0aba2574898011e581c3babcffc6102ec25ced40e1a24fba20371925c46f0299b2b9456360e004c0127d8799f581cdb0d968cda2cc636b28c0f377e66691a065b8004e57be5129aeef8224461757468ff004c01051a000f4240004c01021832004c01021832004c010105000100581d7177799e0f07f377c76676fe9232b9b0bc57ca92c56132817c1ba06d0b"
18
+ )
19
+ )
20
+ })
21
+ })
@@ -0,0 +1,66 @@
1
+ import { Effect, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import * as Cbor from "../Cbor.js"
4
+ import * as TxOutput from "./TxOutput.js"
5
+ import * as TxOutputId from "./TxOutputId.js"
6
+
7
+ export const TxInput = Schema.TaggedStruct("TxInput", {
8
+ id: TxOutputId.TxOutputId,
9
+ output: Schema.optional(TxOutput.TxOutput)
10
+ })
11
+
12
+ export type TxInput = Schema.Schema.Type<typeof TxInput>
13
+
14
+ export function make(
15
+ id: TxOutputId.TxOutputId,
16
+ output: TxOutput.TxOutput | undefined = undefined
17
+ ): TxInput {
18
+ return {
19
+ _tag: "TxInput",
20
+ id,
21
+ output
22
+ }
23
+ }
24
+
25
+ export const decode = (bytes: Bytes.BytesLike): Cbor.DecodeEffect<TxInput> =>
26
+ Effect.gen(function* () {
27
+ const stream = Bytes.makeStream(bytes)
28
+
29
+ if (yield* (yield* Cbor.decodeTupleLazy(stream.copy()))(Cbor.isBytes)) {
30
+ const id = yield* TxOutputId.decode(stream)
31
+
32
+ return make(id)
33
+ } else if (
34
+ yield* (yield* Cbor.decodeTupleLazy(stream.copy()))(Cbor.isTuple)
35
+ ) {
36
+ const [id, output] = yield* Cbor.decodeTuple([
37
+ TxOutputId.decode,
38
+ TxOutput.decode
39
+ ])(stream)
40
+
41
+ return make(id, output)
42
+ } else {
43
+ return yield* Effect.fail(
44
+ new Cbor.DecodeError(stream, "unhandled TxInput encoding")
45
+ )
46
+ }
47
+ })
48
+
49
+ export function encode(txInput: TxInput, full: boolean = false) {
50
+ if (full) {
51
+ return Cbor.encodeTuple([
52
+ TxOutputId.encode(txInput.id),
53
+ TxOutput.encode(output(txInput))
54
+ ])
55
+ } else {
56
+ return TxOutputId.encode(txInput.id)
57
+ }
58
+ }
59
+
60
+ export function output(txInput: TxInput): TxOutput.TxOutput {
61
+ if (!txInput.output) {
62
+ throw new Error("txInput.output not available")
63
+ }
64
+
65
+ return txInput.output
66
+ }
@@ -0,0 +1,166 @@
1
+ import { Effect, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import * as Cbor from "../Cbor.js"
4
+ import * as Address from "./Address.js"
5
+ import * as Assets from "./Assets.js"
6
+ import * as DatumHash from "./DatumHash.js"
7
+ import * as TxOutputDatum from "./TxOutputDatum.js"
8
+
9
+ export const TxOutputEncodingConfig = Schema.Struct({
10
+ strictBabbage: Schema.optional(Schema.Boolean)
11
+ })
12
+
13
+ export type TxOutputEncodingConfig = Schema.Schema.Type<
14
+ typeof TxOutputEncodingConfig
15
+ >
16
+
17
+ export const DEFAULT_TX_OUTPUT_ENCODING_CONFIG: TxOutputEncodingConfig = {
18
+ strictBabbage: true
19
+ }
20
+
21
+ // TODO: add ref script
22
+ export const TxOutput = Schema.TaggedStruct("TxOutput", {
23
+ address: Address.Address,
24
+ assets: Assets.Assets,
25
+ datum: Schema.optional(TxOutputDatum.TxOutputDatum),
26
+ refScript: Schema.optional(Schema.Uint8ArrayFromSelf),
27
+ encodingConfig: Schema.Struct({
28
+ strictBabbage: Schema.optional(Schema.Boolean)
29
+ })
30
+ })
31
+
32
+ export type TxOutput = Schema.Schema.Type<typeof TxOutput>
33
+
34
+ export function make({
35
+ address,
36
+ assets,
37
+ datum = undefined,
38
+ refScript = undefined,
39
+ encodingConfig = DEFAULT_TX_OUTPUT_ENCODING_CONFIG
40
+ }: {
41
+ address: Address.Address
42
+ assets: Assets.Assets
43
+ datum?: TxOutputDatum.TxOutputDatum
44
+ refScript?: Uint8Array
45
+ encodingConfig?: TxOutputEncodingConfig
46
+ }): TxOutput {
47
+ return {
48
+ _tag: "TxOutput",
49
+ address,
50
+ assets,
51
+ datum,
52
+ refScript,
53
+ encodingConfig
54
+ }
55
+ }
56
+
57
+ export const decode = (bytes: Bytes.BytesLike): Cbor.DecodeEffect<TxOutput> =>
58
+ Effect.gen(function* () {
59
+ const stream = Bytes.makeStream(bytes)
60
+ if (yield* Cbor.isObject(bytes)) {
61
+ const {
62
+ 0: address,
63
+ 1: assets,
64
+ 2: datum,
65
+ 3: refScript
66
+ } = yield* Cbor.decodeObjectIKey({
67
+ 0: Address.decode,
68
+ 1: Assets.decode,
69
+ 2: TxOutputDatum.decode,
70
+ 3: (stream): Cbor.DecodeEffect<number[]> =>
71
+ Effect.gen(function* () {
72
+ if ((yield* Cbor.decodeTag(stream)) != 24n) {
73
+ return yield* new Cbor.DecodeError(
74
+ stream,
75
+ "unexpected reference script tag"
76
+ )
77
+ }
78
+
79
+ return yield* Cbor.decodeBytes(stream)
80
+ })
81
+ })(stream)
82
+
83
+ if (!address) {
84
+ return yield* new Cbor.DecodeError(stream, "address field missing")
85
+ }
86
+
87
+ if (!assets) {
88
+ return yield* new Cbor.DecodeError(stream, "assets field missing")
89
+ }
90
+
91
+ return make({
92
+ address,
93
+ assets,
94
+ ...(datum ? { datum } : {}),
95
+ ...(refScript ? { refScript: new Uint8Array(refScript) } : {}),
96
+ encodingConfig: { strictBabbage: true }
97
+ })
98
+ } else if (yield* Cbor.isTuple(bytes)) {
99
+ const [address, assets, datumHash] = yield* Cbor.decodeTuple(
100
+ [Address.decode, Assets.decode],
101
+ [DatumHash.decode]
102
+ )(stream)
103
+
104
+ return make({
105
+ address,
106
+ assets,
107
+ ...(datumHash ? { _tag: "Hash", hash: datumHash } : {}),
108
+ encodingConfig: {
109
+ strictBabbage: false
110
+ }
111
+ })
112
+ } else {
113
+ return yield* new Cbor.DecodeError(stream, "unexpected TxOutput encoding")
114
+ }
115
+ })
116
+
117
+ export function encode(txOutput: TxOutput): number[] {
118
+ if (
119
+ (!txOutput.datum || txOutput.datum._tag == "Hash") &&
120
+ !txOutput.refScript &&
121
+ (txOutput.encodingConfig.strictBabbage == null ||
122
+ !txOutput.encodingConfig.strictBabbage)
123
+ ) {
124
+ // this is needed to match eternl wallet (de)serialization (annoyingly eternl deserializes the tx and then signs its own serialization)
125
+ // hopefully cardano-cli signs whatever serialization we choose (so we use the eternl variant in order to be compatible with both)
126
+
127
+ const fields = [
128
+ Address.encode(txOutput.address),
129
+ Assets.encode(txOutput.assets)
130
+ ]
131
+
132
+ if (txOutput.datum && txOutput.datum._tag == "Hash") {
133
+ fields.push(DatumHash.encode(txOutput.datum.hash))
134
+ }
135
+
136
+ return Cbor.encodeTuple(fields)
137
+ } else {
138
+ const object: Map<number, number[]> = new Map()
139
+
140
+ object.set(0, Address.encode(txOutput.address))
141
+ object.set(1, Assets.encode(txOutput.assets))
142
+
143
+ if (txOutput.datum) {
144
+ object.set(2, TxOutputDatum.encode(txOutput.datum))
145
+ }
146
+
147
+ if (txOutput.refScript) {
148
+ throw new Error("not yet implemented")
149
+ //object.set(
150
+ // 3,
151
+ // Cbor.encodeTag(24n).concat(
152
+ // Cbor.encodeBytes(
153
+ // Cbor.encodeTuple([
154
+ // Cbor.encodeInt(
155
+ // BigInt(this.refScript.plutusVersionTag)
156
+ // ),
157
+ // txOutput.refScript
158
+ // ])
159
+ // )
160
+ // )
161
+ //)
162
+ }
163
+
164
+ return Cbor.encodeObjectIKey(object)
165
+ }
166
+ }
@@ -0,0 +1,64 @@
1
+ import { Effect, Schema } from "effect"
2
+ import * as Bytes from "../internal/Bytes.js"
3
+ import * as Cbor from "../Cbor.js"
4
+ import { Data } from "../Uplc"
5
+ import * as DatumHash from "./DatumHash.js"
6
+
7
+ export const TxOutputDatum = Schema.Union(
8
+ Schema.TaggedStruct("Inline", { data: Data.Data }),
9
+ Schema.TaggedStruct("Hash", { hash: DatumHash.DatumHash })
10
+ )
11
+
12
+ export type TxOutputDatum = Schema.Schema.Type<typeof TxOutputDatum>
13
+
14
+ export const decode = (
15
+ bytes: Bytes.BytesLike
16
+ ): Cbor.DecodeEffect<TxOutputDatum> =>
17
+ Effect.gen(function* () {
18
+ const [type, decodeItem] = yield* Cbor.decodeTagged(bytes)
19
+
20
+ switch (type) {
21
+ case 0:
22
+ return { _tag: "Hash", hash: yield* decodeItem(DatumHash.decode) }
23
+ case 1:
24
+ return {
25
+ _tag: "Inline",
26
+ data: yield* decodeItem((stream: Bytes.Stream) =>
27
+ Effect.gen(function* () {
28
+ const tag = yield* Cbor.decodeTag(stream)
29
+ if (tag != 24n) {
30
+ return yield* Effect.fail(
31
+ new Cbor.DecodeError(stream, `expected 24 as tag, got ${tag}`)
32
+ )
33
+ }
34
+
35
+ return yield* Data.decode(yield* Cbor.decodeBytes(stream))
36
+ })
37
+ )
38
+ }
39
+ default:
40
+ return yield* Effect.fail(
41
+ new Cbor.DecodeError(
42
+ Bytes.makeStream(bytes),
43
+ `unhandled TxOutputDatum type ${type}`
44
+ )
45
+ )
46
+ }
47
+ })
48
+
49
+ export function encode(txOutputDatum: TxOutputDatum): number[] {
50
+ switch (txOutputDatum._tag) {
51
+ case "Hash":
52
+ return Cbor.encodeTuple([
53
+ Cbor.encodeInt(0n),
54
+ DatumHash.encode(txOutputDatum.hash)
55
+ ])
56
+ case "Inline":
57
+ return Cbor.encodeTuple([
58
+ Cbor.encodeInt(1n),
59
+ Cbor.encodeTag(24n).concat(
60
+ Cbor.encodeBytes(Data.encode(txOutputDatum.data))
61
+ )
62
+ ])
63
+ }
64
+ }