@effectstream/sm 0.100.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.
- package/Stm.ts +88 -0
- package/delegate-wallet.ts +431 -0
- package/mod.ts +4 -0
- package/package.json +27 -0
- package/primitives/Primitive.ts +80 -0
- package/primitives/PrimitiveRegistry.ts +59 -0
- package/primitives/mod.ts +5 -0
- package/primitives/processing.ts +72 -0
- package/primitives/src/README.md +3 -0
- package/primitives/src/avail-generic/avail-generic-grammar.ts +5 -0
- package/primitives/src/avail-generic/avail-primitive.ts +103 -0
- package/primitives/src/bitcoin-address/bitcoin-grammar.ts +16 -0
- package/primitives/src/bitcoin-address/bitcoin-primitive.ts +113 -0
- package/primitives/src/builtin.ts +47 -0
- package/primitives/src/celestia-generic/celestia-generic-grammar.ts +5 -0
- package/primitives/src/celestia-generic/celestia-primitive.ts +97 -0
- package/primitives/src/evm-effectstream-l2/effectstream-l2-abi.ts +1 -0
- package/primitives/src/evm-effectstream-l2/effectstream-l2-primitive.ts +484 -0
- package/primitives/src/evm-erc1155/erc1155-abi.ts +1 -0
- package/primitives/src/evm-erc1155/erc1155-grammar.ts +13 -0
- package/primitives/src/evm-erc1155/erc1155-ivm.ts +104 -0
- package/primitives/src/evm-erc1155/erc1155-primitive.ts +242 -0
- package/primitives/src/evm-erc20/erc20-abi.ts +1 -0
- package/primitives/src/evm-erc20/erc20-grammar.ts +7 -0
- package/primitives/src/evm-erc20/erc20-ivm.ts +93 -0
- package/primitives/src/evm-erc20/erc20-primitive.test.ts +123 -0
- package/primitives/src/evm-erc20/erc20-primitive.ts +152 -0
- package/primitives/src/evm-erc721/erc721-abi.ts +1 -0
- package/primitives/src/evm-erc721/erc721-grammar.ts +9 -0
- package/primitives/src/evm-erc721/erc721-ivm.ts +85 -0
- package/primitives/src/evm-erc721/erc721-primitive.ts +149 -0
- package/primitives/src/evm-generic/evm-generic-primitive.ts +124 -0
- package/primitives/src/grammar.ts +34 -0
- package/primitives/src/midnight-generic/midnight-genetic-grammar.ts +8 -0
- package/primitives/src/midnight-generic/midnight-genetic.ts +271 -0
- package/primitives/src/midnight-nullifier/midnight-nullifier-grammar.ts +8 -0
- package/primitives/src/midnight-nullifier/midnight-nullifier.ts +114 -0
- package/primitives/src/mod.ts +81 -0
- package/primitives/src/near-account-watch/near-account-watch-grammar.ts +10 -0
- package/primitives/src/near-account-watch/near-account-watch-primitive.ts +106 -0
- package/primitives/src/near-generic/near-generic-grammar.ts +5 -0
- package/primitives/src/near-generic/near-generic-primitive.ts +105 -0
- package/primitives/src/near-intent/near-intent-grammar.ts +10 -0
- package/primitives/src/near-intent/near-intent-ivm.ts +71 -0
- package/primitives/src/near-intent/near-intent-primitive.ts +149 -0
- package/primitives/src/near-intent/near-intent-token-id-parser.ts +47 -0
- package/primitives/src/near-nep141/nep141-grammar.ts +7 -0
- package/primitives/src/near-nep141/nep141-ivm.ts +70 -0
- package/primitives/src/near-nep141/nep141-primitive.ts +117 -0
- package/primitives/src/near-nep171/nep171-grammar.ts +8 -0
- package/primitives/src/near-nep171/nep171-ivm.ts +71 -0
- package/primitives/src/near-nep171/nep171-primitive.ts +138 -0
- package/primitives/src/near-nep245/nep245-grammar.ts +11 -0
- package/primitives/src/near-nep245/nep245-ivm.ts +84 -0
- package/primitives/src/near-nep245/nep245-primitive.ts +147 -0
- package/primitives/src/utxorpc-generic/utxorpc-generic-grammar.ts +6 -0
- package/primitives/src/utxorpc-generic/utxorpc-generic.ts +88 -0
- package/primitives/types.ts +14 -0
- package/types.ts +28 -0
- package/verify-signature.ts +51 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Value } from "@sinclair/typebox/value";
|
|
2
|
+
import { type StaticDecode, Type } from "@sinclair/typebox";
|
|
3
|
+
import {
|
|
4
|
+
type ConfigSyncProtocolType,
|
|
5
|
+
type FlattenSyncProtocolIOFor,
|
|
6
|
+
getEvmEvent,
|
|
7
|
+
type ProtocolPrimitiveMap,
|
|
8
|
+
} from "@effectstream/config";
|
|
9
|
+
import {
|
|
10
|
+
type AddressAndType,
|
|
11
|
+
AddressType,
|
|
12
|
+
type EvmAddress,
|
|
13
|
+
type EffectstreamBlockNumber,
|
|
14
|
+
TypeboxHelpers,
|
|
15
|
+
} from "@effectstream/utils";
|
|
16
|
+
import { type JsonObject, Primitive } from "@effectstream/sm";
|
|
17
|
+
import {
|
|
18
|
+
type CommandTuple,
|
|
19
|
+
generateRawStmInput,
|
|
20
|
+
type ParamToData,
|
|
21
|
+
} from "@effectstream/concise";
|
|
22
|
+
import type { StateUpdateStream } from "@effectstream/coroutine";
|
|
23
|
+
import { ERC721_VIEW_PREFIX, erc721Ivm } from "./erc721-ivm.ts";
|
|
24
|
+
import { ERC721_INTERMEDIATE_PREFIX } from "./erc721-ivm.ts";
|
|
25
|
+
import { erc721 } from "./erc721-abi.ts";
|
|
26
|
+
import { erc721Grammar } from "./erc721-grammar.ts";
|
|
27
|
+
import { PrimitiveTypeEVMERC721 } from "../builtin.ts";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Erc721 Primitive
|
|
31
|
+
*
|
|
32
|
+
* This is a concrete implementation of the Primitive class for ERC721.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
export class Erc721Primitive extends Primitive<
|
|
37
|
+
ConfigSyncProtocolType.EVM_RPC_PARALLEL,
|
|
38
|
+
typeof erc721Grammar
|
|
39
|
+
> {
|
|
40
|
+
// Primitive defined
|
|
41
|
+
readonly internalTypeName = PrimitiveTypeEVMERC721;
|
|
42
|
+
readonly abi = getEvmEvent(erc721.abi, "Transfer(address,address,uint256)");
|
|
43
|
+
override grammar = erc721Grammar;
|
|
44
|
+
readonly contractAddress: EvmAddress;
|
|
45
|
+
// Dynamic table to track the owner of each token.
|
|
46
|
+
override dynamicTables = erc721Ivm;
|
|
47
|
+
override getIntermediatePrefix(): string[] {
|
|
48
|
+
return [ERC721_INTERMEDIATE_PREFIX];
|
|
49
|
+
}
|
|
50
|
+
override getViewPrefix(): string[] {
|
|
51
|
+
return [ERC721_VIEW_PREFIX];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
constructor(config: {
|
|
55
|
+
instanceName: string;
|
|
56
|
+
startBlockHeight: number;
|
|
57
|
+
contractAddress: EvmAddress;
|
|
58
|
+
stateMachinePrefix: string | undefined;
|
|
59
|
+
}) {
|
|
60
|
+
super(config);
|
|
61
|
+
this.contractAddress = Value.Decode(
|
|
62
|
+
TypeboxHelpers.Evm.Address,
|
|
63
|
+
config.contractAddress,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
override *getPayload(
|
|
68
|
+
_: EffectstreamBlockNumber,
|
|
69
|
+
primitiveTransactionData: FlattenSyncProtocolIOFor<
|
|
70
|
+
ConfigSyncProtocolType.EVM_RPC_PARALLEL
|
|
71
|
+
>,
|
|
72
|
+
): StateUpdateStream<{
|
|
73
|
+
isBatched: boolean;
|
|
74
|
+
data: {
|
|
75
|
+
fromAddressAndType: AddressAndType;
|
|
76
|
+
stateMachinePayload:
|
|
77
|
+
| StaticDecode<
|
|
78
|
+
CommandTuple<string, typeof erc721Grammar>
|
|
79
|
+
>
|
|
80
|
+
| null;
|
|
81
|
+
accountingPayload: JsonObject;
|
|
82
|
+
}[];
|
|
83
|
+
}> {
|
|
84
|
+
const { to, from } = primitiveTransactionData.output.payload;
|
|
85
|
+
const toAddr = Value.Decode(TypeboxHelpers.Evm.Address, to.toLowerCase());
|
|
86
|
+
const fromAddr = Value.Decode(
|
|
87
|
+
TypeboxHelpers.Evm.Address,
|
|
88
|
+
from.toLowerCase(),
|
|
89
|
+
);
|
|
90
|
+
const isBurn = Boolean(toAddr.toLocaleLowerCase().match(/^0x0+(dead)?$/g));
|
|
91
|
+
const tokenId = Value.Decode(
|
|
92
|
+
TypeboxHelpers.Uint256,
|
|
93
|
+
primitiveTransactionData.output.payload.tokenId,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const isBatched = false;
|
|
97
|
+
const accountingPayload: ParamToData<typeof erc721Grammar> = {
|
|
98
|
+
to: toAddr,
|
|
99
|
+
from: fromAddr,
|
|
100
|
+
tokenId: tokenId,
|
|
101
|
+
isBurn: isBurn,
|
|
102
|
+
};
|
|
103
|
+
const stateMachinePayload:
|
|
104
|
+
| StaticDecode<
|
|
105
|
+
CommandTuple<string, typeof this.grammar>
|
|
106
|
+
>
|
|
107
|
+
| null = this.stateMachinePrefix
|
|
108
|
+
? generateRawStmInput(
|
|
109
|
+
this.grammar,
|
|
110
|
+
this.stateMachinePrefix,
|
|
111
|
+
accountingPayload,
|
|
112
|
+
)
|
|
113
|
+
: null;
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
isBatched,
|
|
117
|
+
data: [
|
|
118
|
+
{
|
|
119
|
+
fromAddressAndType: {
|
|
120
|
+
type: AddressType.NONE,
|
|
121
|
+
address: "0x0",
|
|
122
|
+
},
|
|
123
|
+
accountingPayload,
|
|
124
|
+
stateMachinePayload,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
override getConfig(): ProtocolPrimitiveMap[
|
|
131
|
+
ConfigSyncProtocolType.EVM_RPC_PARALLEL
|
|
132
|
+
] {
|
|
133
|
+
return {
|
|
134
|
+
name: this.instanceName,
|
|
135
|
+
type: this.internalTypeName,
|
|
136
|
+
startBlockHeight: this.startBlockHeight,
|
|
137
|
+
contractAddress: this.contractAddress as EvmAddress,
|
|
138
|
+
abi: this.abi,
|
|
139
|
+
// TODO This should be optional.
|
|
140
|
+
scheduledPrefix: this.stateMachinePrefix ?? "",
|
|
141
|
+
} as const;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// declare module "@effectstream/sm" {
|
|
146
|
+
// interface PrimitiveGlobalDefinitions {
|
|
147
|
+
// Erc721Primitive: typeof Erc721Primitive;
|
|
148
|
+
// }
|
|
149
|
+
// }
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { StaticDecode, TSchema } from "@sinclair/typebox";
|
|
2
|
+
import type {
|
|
3
|
+
ConfigSyncProtocolType,
|
|
4
|
+
FlattenSyncProtocolIOFor,
|
|
5
|
+
getEvmEvent,
|
|
6
|
+
ProtocolPrimitiveMap,
|
|
7
|
+
} from "@effectstream/config";
|
|
8
|
+
import {
|
|
9
|
+
type AddressAndType,
|
|
10
|
+
AddressType,
|
|
11
|
+
type EvmAddress,
|
|
12
|
+
type EffectstreamBlockNumber,
|
|
13
|
+
TypeboxHelpers,
|
|
14
|
+
} from "@effectstream/utils";
|
|
15
|
+
import { type JsonObject, Primitive } from "@effectstream/sm";
|
|
16
|
+
import { Value } from "@sinclair/typebox/value";
|
|
17
|
+
import {
|
|
18
|
+
type CommandTuple,
|
|
19
|
+
generateRawStmInput,
|
|
20
|
+
type ParamToData,
|
|
21
|
+
} from "@effectstream/concise";
|
|
22
|
+
import type { StateUpdateStream } from "@effectstream/coroutine";
|
|
23
|
+
import { PrimitiveTypeEVMGeneric } from "../builtin.ts";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Erc20 Primitive
|
|
27
|
+
*
|
|
28
|
+
* This is a concrete implementation of the Primitive class for ERC20.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export class EvmGenericPrimitive extends Primitive<
|
|
32
|
+
ConfigSyncProtocolType.EVM_RPC_PARALLEL,
|
|
33
|
+
readonly [string, TSchema][]
|
|
34
|
+
> {
|
|
35
|
+
// Primitive defined
|
|
36
|
+
readonly internalTypeName = PrimitiveTypeEVMGeneric;
|
|
37
|
+
readonly abi: ReturnType<typeof getEvmEvent>;
|
|
38
|
+
override grammar: readonly [string, TSchema][];
|
|
39
|
+
readonly contractAddress: EvmAddress;
|
|
40
|
+
|
|
41
|
+
constructor(config: {
|
|
42
|
+
instanceName: string;
|
|
43
|
+
startBlockHeight: number;
|
|
44
|
+
contractAddress: EvmAddress;
|
|
45
|
+
stateMachinePrefix: string | undefined;
|
|
46
|
+
abi: ReturnType<typeof getEvmEvent>;
|
|
47
|
+
grammar: readonly [string, TSchema][];
|
|
48
|
+
}) {
|
|
49
|
+
super(config);
|
|
50
|
+
this.contractAddress = Value.Decode(
|
|
51
|
+
TypeboxHelpers.Evm.Address,
|
|
52
|
+
config.contractAddress,
|
|
53
|
+
);
|
|
54
|
+
this.abi = config.abi;
|
|
55
|
+
this.grammar = config.grammar;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override *getPayload(
|
|
59
|
+
_: EffectstreamBlockNumber,
|
|
60
|
+
primitiveTransactionData: FlattenSyncProtocolIOFor<
|
|
61
|
+
ConfigSyncProtocolType.EVM_RPC_PARALLEL
|
|
62
|
+
>,
|
|
63
|
+
): StateUpdateStream<{
|
|
64
|
+
isBatched: boolean;
|
|
65
|
+
data: {
|
|
66
|
+
fromAddressAndType: AddressAndType;
|
|
67
|
+
stateMachinePayload:
|
|
68
|
+
| StaticDecode<
|
|
69
|
+
CommandTuple<string, any>
|
|
70
|
+
>
|
|
71
|
+
| null;
|
|
72
|
+
accountingPayload: JsonObject;
|
|
73
|
+
}[];
|
|
74
|
+
}> {
|
|
75
|
+
const payload = primitiveTransactionData.output.payload;
|
|
76
|
+
const accountingPayload = this.clearBigInts({
|
|
77
|
+
...payload,
|
|
78
|
+
});
|
|
79
|
+
const stateMachinePayload: any = this.stateMachinePrefix
|
|
80
|
+
? generateRawStmInput(
|
|
81
|
+
this.grammar,
|
|
82
|
+
this.stateMachinePrefix,
|
|
83
|
+
accountingPayload,
|
|
84
|
+
)
|
|
85
|
+
: null;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
isBatched: false,
|
|
89
|
+
data: [
|
|
90
|
+
{
|
|
91
|
+
fromAddressAndType: {
|
|
92
|
+
type: AddressType.NONE,
|
|
93
|
+
address: "0x0",
|
|
94
|
+
},
|
|
95
|
+
accountingPayload,
|
|
96
|
+
stateMachinePayload,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private clearBigInts<T>(value: T): T {
|
|
103
|
+
return JSON.parse(
|
|
104
|
+
JSON.stringify(
|
|
105
|
+
value,
|
|
106
|
+
(_, v) => typeof v === "bigint" ? v.toString() : v,
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
override getConfig(): ProtocolPrimitiveMap[
|
|
113
|
+
ConfigSyncProtocolType.EVM_RPC_PARALLEL
|
|
114
|
+
] {
|
|
115
|
+
return {
|
|
116
|
+
name: this.instanceName,
|
|
117
|
+
type: this.internalTypeName,
|
|
118
|
+
startBlockHeight: this.startBlockHeight,
|
|
119
|
+
contractAddress: this.contractAddress as EvmAddress,
|
|
120
|
+
abi: this.abi,
|
|
121
|
+
scheduledPrefix: this.stateMachinePrefix,
|
|
122
|
+
} as const;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// list of built-in grammars
|
|
2
|
+
// this list is exposed to the effectstream-sdk modules via the @effectstream/sm/grammar module
|
|
3
|
+
|
|
4
|
+
import { midnightGenericGrammar } from "./midnight-generic/midnight-genetic-grammar.ts";
|
|
5
|
+
import { erc721Grammar } from "./evm-erc721/erc721-grammar.ts";
|
|
6
|
+
import { erc20Grammar } from "./evm-erc20/erc20-grammar.ts";
|
|
7
|
+
import { availGenericGrammar } from "./avail-generic/avail-generic-grammar.ts";
|
|
8
|
+
import { erc1155Grammar } from "./evm-erc1155/erc1155-grammar.ts";
|
|
9
|
+
import { bitcoinAddressGrammar } from "./bitcoin-address/bitcoin-grammar.ts";
|
|
10
|
+
import { utxorpcGenericGrammar } from "./utxorpc-generic/utxorpc-generic-grammar.ts";
|
|
11
|
+
import { celestiaGenericGrammar } from "./celestia-generic/celestia-generic-grammar.ts";
|
|
12
|
+
import { nep141Grammar } from "./near-nep141/nep141-grammar.ts";
|
|
13
|
+
import { nep171Grammar } from "./near-nep171/nep171-grammar.ts";
|
|
14
|
+
import { nep245Grammar } from "./near-nep245/nep245-grammar.ts";
|
|
15
|
+
import { nearIntentGrammar } from "./near-intent/near-intent-grammar.ts";
|
|
16
|
+
import { nearGenericGrammar } from "./near-generic/near-generic-grammar.ts";
|
|
17
|
+
import { nearAccountWatchGrammar } from "./near-account-watch/near-account-watch-grammar.ts";
|
|
18
|
+
|
|
19
|
+
export const builtinGrammars = {
|
|
20
|
+
midnightGeneric: midnightGenericGrammar,
|
|
21
|
+
evmErc721: erc721Grammar,
|
|
22
|
+
evmErc20: erc20Grammar,
|
|
23
|
+
availGeneric: availGenericGrammar,
|
|
24
|
+
evmErc1155: erc1155Grammar,
|
|
25
|
+
bitcoinAddress: bitcoinAddressGrammar,
|
|
26
|
+
utxorpcGeneric: utxorpcGenericGrammar,
|
|
27
|
+
celestiaGeneric: celestiaGenericGrammar,
|
|
28
|
+
nearNep141: nep141Grammar,
|
|
29
|
+
nearNep171: nep171Grammar,
|
|
30
|
+
nearNep245: nep245Grammar,
|
|
31
|
+
nearIntent: nearIntentGrammar,
|
|
32
|
+
nearGeneric: nearGenericGrammar,
|
|
33
|
+
nearAccountWatch: nearAccountWatchGrammar,
|
|
34
|
+
} as const;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { Primitive } from "@effectstream/sm";
|
|
2
|
+
import {
|
|
3
|
+
type AddressAndType,
|
|
4
|
+
AddressType,
|
|
5
|
+
type MidnightAddress,
|
|
6
|
+
type EffectstreamBlockNumber,
|
|
7
|
+
uint8ArrayToHexString,
|
|
8
|
+
} from "@effectstream/utils";
|
|
9
|
+
import type { StaticDecode } from "@sinclair/typebox";
|
|
10
|
+
import {
|
|
11
|
+
type CommandTuple,
|
|
12
|
+
generateRawStmInput,
|
|
13
|
+
type ParamToData,
|
|
14
|
+
} from "@effectstream/concise";
|
|
15
|
+
import type {
|
|
16
|
+
ConfigSyncProtocolType,
|
|
17
|
+
FlattenSyncProtocolIOFor,
|
|
18
|
+
LedgerFieldType,
|
|
19
|
+
LedgerSchema,
|
|
20
|
+
ProtocolPrimitiveMap,
|
|
21
|
+
StateValue,
|
|
22
|
+
} from "@effectstream/config";
|
|
23
|
+
import type { SyncStateUpdateStream } from "@effectstream/coroutine";
|
|
24
|
+
import { PrimitiveTypeMidnightGeneric } from "../builtin.ts";
|
|
25
|
+
import { midnightGenericGrammar } from "./midnight-genetic-grammar.ts"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export class MidnightGenericPrimitive extends Primitive<
|
|
29
|
+
ConfigSyncProtocolType.MIDNIGHT_PARALLEL,
|
|
30
|
+
typeof midnightGenericGrammar
|
|
31
|
+
> {
|
|
32
|
+
// Primitive defined
|
|
33
|
+
readonly internalTypeName = PrimitiveTypeMidnightGeneric;
|
|
34
|
+
override readonly grammar = midnightGenericGrammar;
|
|
35
|
+
readonly contractAddress: string;
|
|
36
|
+
readonly contract: {
|
|
37
|
+
ledger: (data: StateValue) => any;
|
|
38
|
+
};
|
|
39
|
+
readonly ledgerSchema?: LedgerSchema;
|
|
40
|
+
readonly networkId: string;
|
|
41
|
+
readonly genesisHash: string;
|
|
42
|
+
// No dynamic tables for midnight generic primitive
|
|
43
|
+
override dynamicTables = undefined;
|
|
44
|
+
override getIntermediatePrefix(): string[] {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
override getViewPrefix(): string[] {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
constructor(config: {
|
|
52
|
+
instanceName: string;
|
|
53
|
+
startBlockHeight: number;
|
|
54
|
+
contractAddress: MidnightAddress;
|
|
55
|
+
stateMachinePrefix: string;
|
|
56
|
+
contract: {
|
|
57
|
+
ledger: (data: StateValue) => any;
|
|
58
|
+
};
|
|
59
|
+
ledgerSchema?: LedgerSchema;
|
|
60
|
+
networkId?: string;
|
|
61
|
+
genesisHash?: string;
|
|
62
|
+
}) {
|
|
63
|
+
super(config);
|
|
64
|
+
this.contractAddress = config.contractAddress;
|
|
65
|
+
this.contract = config.contract;
|
|
66
|
+
this.ledgerSchema = config.ledgerSchema;
|
|
67
|
+
this.networkId = config.networkId ?? "undeployed";
|
|
68
|
+
this.genesisHash = config.genesisHash || "";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parses ledger fields from the raw Midnight StateValue using the `ledgerSchema`.
|
|
73
|
+
* The schema keys must be in Compact declaration order — the parser maps each key
|
|
74
|
+
* to the corresponding positional index in the state array.
|
|
75
|
+
*/
|
|
76
|
+
parseAdditionalLedgerFields(stateValue: StateValue): Record<string, any> {
|
|
77
|
+
if (!this.ledgerSchema) return {};
|
|
78
|
+
|
|
79
|
+
const stateArray: StateValue[] = stateValue.asArray?.() ?? [];
|
|
80
|
+
const result: Record<string, any> = {};
|
|
81
|
+
const schemaEntries = Object.entries(this.ledgerSchema);
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < schemaEntries.length && i < stateArray.length; i++) {
|
|
84
|
+
const [fieldName, fieldType] = schemaEntries[i];
|
|
85
|
+
result[fieldName] = parseLedgerField(stateArray[i], fieldType);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
override *getPayload(
|
|
92
|
+
_: EffectstreamBlockNumber,
|
|
93
|
+
primitiveTransactionData: FlattenSyncProtocolIOFor<
|
|
94
|
+
ConfigSyncProtocolType.MIDNIGHT_PARALLEL
|
|
95
|
+
>,
|
|
96
|
+
): SyncStateUpdateStream<{
|
|
97
|
+
isBatched: boolean;
|
|
98
|
+
data: {
|
|
99
|
+
fromAddressAndType: AddressAndType;
|
|
100
|
+
stateMachinePayload:
|
|
101
|
+
| StaticDecode<CommandTuple<string, typeof midnightGenericGrammar>>
|
|
102
|
+
| null;
|
|
103
|
+
accountingPayload: ParamToData<typeof midnightGenericGrammar>;
|
|
104
|
+
}[];
|
|
105
|
+
}> {
|
|
106
|
+
const payload = primitiveTransactionData.output.payload;
|
|
107
|
+
try {
|
|
108
|
+
const isBatched = false;
|
|
109
|
+
|
|
110
|
+
const accountingPayload: ParamToData<typeof this.grammar> = {
|
|
111
|
+
payload: makeJsonSafe(payload),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const stateMachinePayload:
|
|
115
|
+
| StaticDecode<
|
|
116
|
+
CommandTuple<string, typeof this.grammar>
|
|
117
|
+
>
|
|
118
|
+
| null = this.stateMachinePrefix
|
|
119
|
+
? generateRawStmInput(
|
|
120
|
+
this.grammar,
|
|
121
|
+
this.stateMachinePrefix,
|
|
122
|
+
accountingPayload,
|
|
123
|
+
)
|
|
124
|
+
: null;
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
isBatched,
|
|
128
|
+
data: [
|
|
129
|
+
{
|
|
130
|
+
fromAddressAndType: {
|
|
131
|
+
type: AddressType.NONE,
|
|
132
|
+
address: "0x0",
|
|
133
|
+
},
|
|
134
|
+
accountingPayload,
|
|
135
|
+
stateMachinePayload,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(
|
|
141
|
+
"[ERROR] Decoding Midnight Generic Payload:",
|
|
142
|
+
JSON.stringify(payload),
|
|
143
|
+
);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
override getConfig(): ProtocolPrimitiveMap[
|
|
149
|
+
ConfigSyncProtocolType.MIDNIGHT_PARALLEL
|
|
150
|
+
] {
|
|
151
|
+
return {
|
|
152
|
+
name: this.instanceName,
|
|
153
|
+
type: this.internalTypeName,
|
|
154
|
+
startBlockHeight: this.startBlockHeight,
|
|
155
|
+
contractAddress: this.contractAddress,
|
|
156
|
+
// TODO This should be optional
|
|
157
|
+
scheduledPrefix: this.stateMachinePrefix ?? "",
|
|
158
|
+
contract: this.contract,
|
|
159
|
+
parseAdditionalLedgerFields: this.ledgerSchema
|
|
160
|
+
? this.parseAdditionalLedgerFields.bind(this)
|
|
161
|
+
: undefined,
|
|
162
|
+
// FIXME: historically we relied on NetworkId enum values, but
|
|
163
|
+
// the v1 runtime expects canonical string identifiers instead.
|
|
164
|
+
networkId: this.networkId,
|
|
165
|
+
// TODO This is unused for now.
|
|
166
|
+
genesisHash: this.genesisHash || "",
|
|
167
|
+
} as const;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function alignedValueToHex(value: { value: Uint8Array[] }): string {
|
|
172
|
+
return (
|
|
173
|
+
"0x" +
|
|
174
|
+
value.value
|
|
175
|
+
.map((chunk: Uint8Array) =>
|
|
176
|
+
Array.from(chunk)
|
|
177
|
+
.map((b: number) => b.toString(16).padStart(2, "0"))
|
|
178
|
+
.join("")
|
|
179
|
+
)
|
|
180
|
+
.join("")
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function parseUintCellLittleEndian(chunks: Uint8Array[]): string {
|
|
185
|
+
let result = 0n;
|
|
186
|
+
let shift = 0n;
|
|
187
|
+
for (const chunk of chunks) {
|
|
188
|
+
for (const byte of chunk) {
|
|
189
|
+
result |= BigInt(byte) << shift;
|
|
190
|
+
shift += 8n;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return result.toString();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function parseLedgerField(sv: StateValue, type: LedgerFieldType): any {
|
|
197
|
+
if (typeof type === "object" && type.type === "option") {
|
|
198
|
+
if (sv.type() === "null") return null;
|
|
199
|
+
return parseLedgerField(sv, type.value);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (typeof type === "object" && type.type === "map") {
|
|
203
|
+
const map = sv.asMap();
|
|
204
|
+
if (!map) return {};
|
|
205
|
+
|
|
206
|
+
const result: Record<string, any> = {};
|
|
207
|
+
for (const key of map.keys()) {
|
|
208
|
+
const val = map.get(key);
|
|
209
|
+
if (val !== undefined) {
|
|
210
|
+
result[alignedValueToHex(key as { value: Uint8Array[] })] = parseLedgerField(
|
|
211
|
+
val,
|
|
212
|
+
type.value,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (sv.type() !== "cell") return null;
|
|
220
|
+
const cell = sv.asCell();
|
|
221
|
+
|
|
222
|
+
if (
|
|
223
|
+
type === "uint8" ||
|
|
224
|
+
type === "uint16" ||
|
|
225
|
+
type === "uint32" ||
|
|
226
|
+
type === "uint64" ||
|
|
227
|
+
type === "uint128"
|
|
228
|
+
) {
|
|
229
|
+
return parseUintCellLittleEndian(cell.value as Uint8Array[]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (type === "bytes") {
|
|
233
|
+
return alignedValueToHex(cell as { value: Uint8Array[] });
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (type === "boolean") {
|
|
237
|
+
return (cell.value as Uint8Array[]).some((chunk: Uint8Array) =>
|
|
238
|
+
chunk.some((b: number) => b !== 0)
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function makeJsonSafe(data: unknown): any {
|
|
246
|
+
if (typeof data === 'boolean' || typeof data === 'number' || typeof data === 'string') {
|
|
247
|
+
return data;
|
|
248
|
+
}
|
|
249
|
+
if (typeof data === 'bigint') {
|
|
250
|
+
return data.toString();
|
|
251
|
+
}
|
|
252
|
+
if (data === null || data === undefined) {
|
|
253
|
+
return data;
|
|
254
|
+
}
|
|
255
|
+
if (Array.isArray(data)) {
|
|
256
|
+
return data.map(makeJsonSafe);
|
|
257
|
+
}
|
|
258
|
+
if (data instanceof Uint8Array) {
|
|
259
|
+
return uint8ArrayToHexString(data);
|
|
260
|
+
}
|
|
261
|
+
if (typeof data === 'object') {
|
|
262
|
+
return Object.fromEntries(Object.entries(data).map(([k, v]) => [k, makeJsonSafe(v)]));
|
|
263
|
+
}
|
|
264
|
+
return data;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// declare module "@effectstream/sm" {
|
|
268
|
+
// interface PrimitiveGlobalDefinitions {
|
|
269
|
+
// MidnightGenericPrimitive: typeof MidnightGenericPrimitive;
|
|
270
|
+
// }
|
|
271
|
+
// }
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Primitive } from "@effectstream/sm";
|
|
2
|
+
import {
|
|
3
|
+
type AddressAndType,
|
|
4
|
+
AddressType,
|
|
5
|
+
type EffectstreamBlockNumber,
|
|
6
|
+
} from "@effectstream/utils";
|
|
7
|
+
import type { StaticDecode } from "@sinclair/typebox";
|
|
8
|
+
import {
|
|
9
|
+
type CommandTuple,
|
|
10
|
+
generateRawStmInput,
|
|
11
|
+
type ParamToData,
|
|
12
|
+
} from "@effectstream/concise";
|
|
13
|
+
import type {
|
|
14
|
+
ConfigSyncProtocolType,
|
|
15
|
+
FlattenSyncProtocolIOFor,
|
|
16
|
+
ProtocolPrimitiveMap,
|
|
17
|
+
} from "@effectstream/config";
|
|
18
|
+
import type { SyncStateUpdateStream } from "@effectstream/coroutine";
|
|
19
|
+
import { PrimitiveTypeMidnightNullifier } from "../builtin.ts";
|
|
20
|
+
import { midnightNullifierGrammar } from "./midnight-nullifier-grammar.ts";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* MidnightNullifierPrimitive
|
|
24
|
+
*
|
|
25
|
+
* Watches all ZswapInput (nullifier-spend) events on the Midnight shielded
|
|
26
|
+
* ledger. One state-machine input is emitted per nullifier event observed in
|
|
27
|
+
* a block, regardless of which contract produced it.
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* stm.addStateTransition("myPrefix", function* (data) {
|
|
31
|
+
* const { payload } = data.parsedInput;
|
|
32
|
+
* // payload = { nullifier, txHash, eventId, logicalSegment }
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
export class MidnightNullifierPrimitive extends Primitive<
|
|
36
|
+
ConfigSyncProtocolType.MIDNIGHT_PARALLEL,
|
|
37
|
+
typeof midnightNullifierGrammar
|
|
38
|
+
> {
|
|
39
|
+
readonly internalTypeName = PrimitiveTypeMidnightNullifier;
|
|
40
|
+
override readonly grammar = midnightNullifierGrammar;
|
|
41
|
+
|
|
42
|
+
override dynamicTables = undefined;
|
|
43
|
+
override getIntermediatePrefix(): string[] {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
override getViewPrefix(): string[] {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
constructor(config: {
|
|
51
|
+
instanceName: string;
|
|
52
|
+
startBlockHeight: number;
|
|
53
|
+
stateMachinePrefix: string;
|
|
54
|
+
}) {
|
|
55
|
+
super(config);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override *getPayload(
|
|
59
|
+
_: EffectstreamBlockNumber,
|
|
60
|
+
primitiveTransactionData: FlattenSyncProtocolIOFor<
|
|
61
|
+
ConfigSyncProtocolType.MIDNIGHT_PARALLEL
|
|
62
|
+
>,
|
|
63
|
+
): SyncStateUpdateStream<{
|
|
64
|
+
isBatched: boolean;
|
|
65
|
+
data: {
|
|
66
|
+
fromAddressAndType: AddressAndType;
|
|
67
|
+
stateMachinePayload:
|
|
68
|
+
| StaticDecode<CommandTuple<string, typeof midnightNullifierGrammar>>
|
|
69
|
+
| null;
|
|
70
|
+
accountingPayload: ParamToData<typeof midnightNullifierGrammar>;
|
|
71
|
+
}[];
|
|
72
|
+
}> {
|
|
73
|
+
const payload = primitiveTransactionData.output.payload;
|
|
74
|
+
|
|
75
|
+
const accountingPayload: ParamToData<typeof this.grammar> = {
|
|
76
|
+
payload,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const stateMachinePayload:
|
|
80
|
+
| StaticDecode<CommandTuple<string, typeof this.grammar>>
|
|
81
|
+
| null = this.stateMachinePrefix
|
|
82
|
+
? generateRawStmInput(
|
|
83
|
+
this.grammar,
|
|
84
|
+
this.stateMachinePrefix,
|
|
85
|
+
accountingPayload,
|
|
86
|
+
)
|
|
87
|
+
: null;
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
isBatched: false,
|
|
91
|
+
data: [
|
|
92
|
+
{
|
|
93
|
+
fromAddressAndType: {
|
|
94
|
+
type: AddressType.NONE,
|
|
95
|
+
address: "0x0",
|
|
96
|
+
},
|
|
97
|
+
accountingPayload,
|
|
98
|
+
stateMachinePayload,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
override getConfig(): ProtocolPrimitiveMap[
|
|
105
|
+
ConfigSyncProtocolType.MIDNIGHT_PARALLEL
|
|
106
|
+
] {
|
|
107
|
+
return {
|
|
108
|
+
name: this.instanceName,
|
|
109
|
+
type: this.internalTypeName,
|
|
110
|
+
startBlockHeight: this.startBlockHeight,
|
|
111
|
+
scheduledPrefix: this.stateMachinePrefix ?? "",
|
|
112
|
+
} as const;
|
|
113
|
+
}
|
|
114
|
+
}
|