@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.
Files changed (60) hide show
  1. package/Stm.ts +88 -0
  2. package/delegate-wallet.ts +431 -0
  3. package/mod.ts +4 -0
  4. package/package.json +27 -0
  5. package/primitives/Primitive.ts +80 -0
  6. package/primitives/PrimitiveRegistry.ts +59 -0
  7. package/primitives/mod.ts +5 -0
  8. package/primitives/processing.ts +72 -0
  9. package/primitives/src/README.md +3 -0
  10. package/primitives/src/avail-generic/avail-generic-grammar.ts +5 -0
  11. package/primitives/src/avail-generic/avail-primitive.ts +103 -0
  12. package/primitives/src/bitcoin-address/bitcoin-grammar.ts +16 -0
  13. package/primitives/src/bitcoin-address/bitcoin-primitive.ts +113 -0
  14. package/primitives/src/builtin.ts +47 -0
  15. package/primitives/src/celestia-generic/celestia-generic-grammar.ts +5 -0
  16. package/primitives/src/celestia-generic/celestia-primitive.ts +97 -0
  17. package/primitives/src/evm-effectstream-l2/effectstream-l2-abi.ts +1 -0
  18. package/primitives/src/evm-effectstream-l2/effectstream-l2-primitive.ts +484 -0
  19. package/primitives/src/evm-erc1155/erc1155-abi.ts +1 -0
  20. package/primitives/src/evm-erc1155/erc1155-grammar.ts +13 -0
  21. package/primitives/src/evm-erc1155/erc1155-ivm.ts +104 -0
  22. package/primitives/src/evm-erc1155/erc1155-primitive.ts +242 -0
  23. package/primitives/src/evm-erc20/erc20-abi.ts +1 -0
  24. package/primitives/src/evm-erc20/erc20-grammar.ts +7 -0
  25. package/primitives/src/evm-erc20/erc20-ivm.ts +93 -0
  26. package/primitives/src/evm-erc20/erc20-primitive.test.ts +123 -0
  27. package/primitives/src/evm-erc20/erc20-primitive.ts +152 -0
  28. package/primitives/src/evm-erc721/erc721-abi.ts +1 -0
  29. package/primitives/src/evm-erc721/erc721-grammar.ts +9 -0
  30. package/primitives/src/evm-erc721/erc721-ivm.ts +85 -0
  31. package/primitives/src/evm-erc721/erc721-primitive.ts +149 -0
  32. package/primitives/src/evm-generic/evm-generic-primitive.ts +124 -0
  33. package/primitives/src/grammar.ts +34 -0
  34. package/primitives/src/midnight-generic/midnight-genetic-grammar.ts +8 -0
  35. package/primitives/src/midnight-generic/midnight-genetic.ts +271 -0
  36. package/primitives/src/midnight-nullifier/midnight-nullifier-grammar.ts +8 -0
  37. package/primitives/src/midnight-nullifier/midnight-nullifier.ts +114 -0
  38. package/primitives/src/mod.ts +81 -0
  39. package/primitives/src/near-account-watch/near-account-watch-grammar.ts +10 -0
  40. package/primitives/src/near-account-watch/near-account-watch-primitive.ts +106 -0
  41. package/primitives/src/near-generic/near-generic-grammar.ts +5 -0
  42. package/primitives/src/near-generic/near-generic-primitive.ts +105 -0
  43. package/primitives/src/near-intent/near-intent-grammar.ts +10 -0
  44. package/primitives/src/near-intent/near-intent-ivm.ts +71 -0
  45. package/primitives/src/near-intent/near-intent-primitive.ts +149 -0
  46. package/primitives/src/near-intent/near-intent-token-id-parser.ts +47 -0
  47. package/primitives/src/near-nep141/nep141-grammar.ts +7 -0
  48. package/primitives/src/near-nep141/nep141-ivm.ts +70 -0
  49. package/primitives/src/near-nep141/nep141-primitive.ts +117 -0
  50. package/primitives/src/near-nep171/nep171-grammar.ts +8 -0
  51. package/primitives/src/near-nep171/nep171-ivm.ts +71 -0
  52. package/primitives/src/near-nep171/nep171-primitive.ts +138 -0
  53. package/primitives/src/near-nep245/nep245-grammar.ts +11 -0
  54. package/primitives/src/near-nep245/nep245-ivm.ts +84 -0
  55. package/primitives/src/near-nep245/nep245-primitive.ts +147 -0
  56. package/primitives/src/utxorpc-generic/utxorpc-generic-grammar.ts +6 -0
  57. package/primitives/src/utxorpc-generic/utxorpc-generic.ts +88 -0
  58. package/primitives/types.ts +14 -0
  59. package/types.ts +28 -0
  60. package/verify-signature.ts +51 -0
@@ -0,0 +1,117 @@
1
+ import type { StaticDecode } from "@sinclair/typebox";
2
+ import {
3
+ type ConfigSyncProtocolType,
4
+ type FlattenSyncProtocolIOFor,
5
+ type ProtocolPrimitiveMap,
6
+ } from "@effectstream/config";
7
+ import {
8
+ type AddressAndType,
9
+ AddressType,
10
+ type EffectstreamBlockNumber,
11
+ } from "@effectstream/utils";
12
+ import { type JsonObject, Primitive } from "@effectstream/sm";
13
+ import {
14
+ type CommandTuple,
15
+ generateRawStmInput,
16
+ type ParamToData,
17
+ } from "@effectstream/concise";
18
+ import type { StateUpdateStream } from "@effectstream/coroutine";
19
+ import { nep141Grammar } from "./nep141-grammar.ts";
20
+ import {
21
+ NEP141_INTERMEDIATE_PREFIX,
22
+ NEP141_VIEW_PREFIX,
23
+ nep141Ivm,
24
+ } from "./nep141-ivm.ts";
25
+ import { PrimitiveTypeNEARNEP141 } from "../builtin.ts";
26
+
27
+ export class Nep141Primitive extends Primitive<
28
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL,
29
+ typeof nep141Grammar
30
+ > {
31
+ readonly internalTypeName = PrimitiveTypeNEARNEP141;
32
+ override grammar = nep141Grammar;
33
+ readonly contractId: string;
34
+
35
+ override dynamicTables = nep141Ivm;
36
+ override getIntermediatePrefix(): string[] {
37
+ return [NEP141_INTERMEDIATE_PREFIX];
38
+ }
39
+ override getViewPrefix(): string[] {
40
+ return [NEP141_VIEW_PREFIX];
41
+ }
42
+
43
+ constructor(config: {
44
+ instanceName: string;
45
+ startBlockHeight: number;
46
+ contractId: string;
47
+ stateMachinePrefix: string | undefined;
48
+ }) {
49
+ super(config);
50
+ this.contractId = config.contractId;
51
+ }
52
+
53
+ override *getPayload(
54
+ _: EffectstreamBlockNumber,
55
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
56
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
57
+ >,
58
+ ): StateUpdateStream<{
59
+ isBatched: boolean;
60
+ data: {
61
+ fromAddressAndType: AddressAndType;
62
+ stateMachinePayload:
63
+ | StaticDecode<CommandTuple<string, typeof nep141Grammar>>
64
+ | null;
65
+ accountingPayload: JsonObject;
66
+ }[];
67
+ }> {
68
+ const payload = primitiveTransactionData.output.payload as Record<string, unknown>;
69
+ const oldOwnerId = String(payload.old_owner_id ?? "");
70
+ const newOwnerId = String(payload.new_owner_id ?? "");
71
+ const amount = String(payload.amount ?? "0");
72
+
73
+ const accountingPayload: ParamToData<typeof nep141Grammar> = {
74
+ old_owner_id: oldOwnerId,
75
+ new_owner_id: newOwnerId,
76
+ amount,
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.NEAR,
95
+ address: oldOwnerId,
96
+ },
97
+ accountingPayload,
98
+ stateMachinePayload,
99
+ },
100
+ ],
101
+ };
102
+ }
103
+
104
+ override getConfig(): ProtocolPrimitiveMap[
105
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
106
+ ] {
107
+ return {
108
+ name: this.instanceName,
109
+ type: this.internalTypeName,
110
+ startBlockHeight: this.startBlockHeight,
111
+ contractId: this.contractId,
112
+ eventStandard: "nep141",
113
+ eventType: "ft_transfer",
114
+ scheduledPrefix: this.stateMachinePrefix,
115
+ };
116
+ }
117
+ }
@@ -0,0 +1,8 @@
1
+ import { Type } from "@sinclair/typebox";
2
+
3
+ export const nep171Grammar = [
4
+ ['old_owner_id', Type.String()],
5
+ ['new_owner_id', Type.String()],
6
+ ['token_id', Type.String()],
7
+ ['isBurn', Type.Boolean()],
8
+ ] as const;
@@ -0,0 +1,71 @@
1
+ import { PrimitiveTypeNEARNEP171 } from "../builtin.ts";
2
+
3
+ export function nep171Ivm(name: string) {
4
+ const lowerName = name.toLowerCase();
5
+ const validSQLName = lowerName.replace(/[^a-zA-Z0-9_]/g, "");
6
+ if (validSQLName !== lowerName) {
7
+ throw new Error(`Invalid name: ${name}`);
8
+ }
9
+
10
+ const ownerTable = `primitives.nep171_owner_intermediate_${validSQLName}`;
11
+
12
+ return `
13
+ CREATE TABLE IF NOT EXISTS ${ownerTable} (
14
+ primitive_name TEXT NOT NULL,
15
+ token_id TEXT NOT NULL,
16
+ current_owner TEXT NOT NULL,
17
+ last_transfer_block_height INTEGER NOT NULL,
18
+ last_transfer_id INTEGER NOT NULL,
19
+ PRIMARY KEY (primitive_name, token_id)
20
+ );
21
+
22
+ CREATE OR REPLACE FUNCTION update_nep171_owner_${validSQLName}() RETURNS TRIGGER AS $$
23
+ DECLARE
24
+ new_owner TEXT;
25
+ nft_token_id TEXT;
26
+ is_burn BOOLEAN;
27
+ BEGIN
28
+ IF NEW.payload_type = '${PrimitiveTypeNEARNEP171}'
29
+ AND NEW.primitive_name = '${name}' THEN
30
+
31
+ new_owner := NEW.payload->>'new_owner_id';
32
+ nft_token_id := NEW.payload->>'token_id';
33
+ is_burn := (NEW.payload->>'isBurn')::boolean;
34
+
35
+ IF nft_token_id IS NOT NULL AND NOT is_burn THEN
36
+ INSERT INTO ${ownerTable} (primitive_name, token_id, current_owner, last_transfer_block_height, last_transfer_id)
37
+ VALUES (NEW.primitive_name, nft_token_id, new_owner, NEW.effectstream_block_height, NEW.id)
38
+ ON CONFLICT (primitive_name, token_id) DO UPDATE SET
39
+ current_owner = new_owner,
40
+ last_transfer_block_height = NEW.effectstream_block_height,
41
+ last_transfer_id = NEW.id
42
+ WHERE ${ownerTable}.last_transfer_block_height < NEW.effectstream_block_height
43
+ OR (${ownerTable}.last_transfer_block_height = NEW.effectstream_block_height
44
+ AND ${ownerTable}.last_transfer_id < NEW.id);
45
+ ELSIF nft_token_id IS NOT NULL AND is_burn THEN
46
+ DELETE FROM ${ownerTable}
47
+ WHERE primitive_name = NEW.primitive_name AND token_id = nft_token_id;
48
+ END IF;
49
+ END IF;
50
+
51
+ RETURN NEW;
52
+ END;
53
+ $$ LANGUAGE plpgsql;
54
+
55
+ CREATE TRIGGER trigger_update_nep171_owner_${validSQLName}
56
+ AFTER INSERT ON effectstream.primitive_accounting
57
+ FOR EACH ROW
58
+ EXECUTE FUNCTION update_nep171_owner_${validSQLName}();
59
+
60
+ SELECT pgivm.create_immv('primitives.nep171_owner_view_${validSQLName}',
61
+ 'SELECT
62
+ primitive_name,
63
+ token_id,
64
+ current_owner
65
+ FROM ${ownerTable};
66
+ ');
67
+ `;
68
+ }
69
+
70
+ export const NEP171_VIEW_PREFIX = "nep171_owner_view_" as const;
71
+ export const NEP171_INTERMEDIATE_PREFIX = "nep171_owner_intermediate_" as const;
@@ -0,0 +1,138 @@
1
+ import type { StaticDecode } from "@sinclair/typebox";
2
+ import {
3
+ type ConfigSyncProtocolType,
4
+ type FlattenSyncProtocolIOFor,
5
+ type ProtocolPrimitiveMap,
6
+ } from "@effectstream/config";
7
+ import {
8
+ type AddressAndType,
9
+ AddressType,
10
+ type EffectstreamBlockNumber,
11
+ } from "@effectstream/utils";
12
+ import { type JsonObject, Primitive } from "@effectstream/sm";
13
+ import {
14
+ type CommandTuple,
15
+ generateRawStmInput,
16
+ type ParamToData,
17
+ } from "@effectstream/concise";
18
+ import type { StateUpdateStream } from "@effectstream/coroutine";
19
+ import { nep171Grammar } from "./nep171-grammar.ts";
20
+ import {
21
+ NEP171_INTERMEDIATE_PREFIX,
22
+ NEP171_VIEW_PREFIX,
23
+ nep171Ivm,
24
+ } from "./nep171-ivm.ts";
25
+ import { PrimitiveTypeNEARNEP171 } from "../builtin.ts";
26
+
27
+ const BURN_RECEIVER = "system";
28
+
29
+ export class Nep171Primitive extends Primitive<
30
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL,
31
+ typeof nep171Grammar
32
+ > {
33
+ readonly internalTypeName = PrimitiveTypeNEARNEP171;
34
+ override grammar = nep171Grammar;
35
+ readonly contractId: string;
36
+
37
+ override dynamicTables = nep171Ivm;
38
+ override getIntermediatePrefix(): string[] {
39
+ return [NEP171_INTERMEDIATE_PREFIX];
40
+ }
41
+ override getViewPrefix(): string[] {
42
+ return [NEP171_VIEW_PREFIX];
43
+ }
44
+
45
+ constructor(config: {
46
+ instanceName: string;
47
+ startBlockHeight: number;
48
+ contractId: string;
49
+ stateMachinePrefix: string | undefined;
50
+ }) {
51
+ super(config);
52
+ this.contractId = config.contractId;
53
+ }
54
+
55
+ override *getPayload(
56
+ _: EffectstreamBlockNumber,
57
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
58
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
59
+ >,
60
+ ): StateUpdateStream<{
61
+ isBatched: boolean;
62
+ data: {
63
+ fromAddressAndType: AddressAndType;
64
+ stateMachinePayload:
65
+ | StaticDecode<CommandTuple<string, typeof nep171Grammar>>
66
+ | null;
67
+ accountingPayload: JsonObject;
68
+ }[];
69
+ }> {
70
+ const payload = primitiveTransactionData.output.payload as Record<string, unknown>;
71
+ const oldOwnerId = String(payload.old_owner_id ?? "");
72
+ const newOwnerId = String(payload.new_owner_id ?? "");
73
+ // NEP-171 events may have token_ids array — emit one per token
74
+ const tokenIds: string[] = Array.isArray(payload.token_ids)
75
+ ? (payload.token_ids as string[])
76
+ : [String(payload.token_ids ?? payload.token_id ?? "")];
77
+
78
+ const isBurn = newOwnerId === "" || newOwnerId === BURN_RECEIVER;
79
+
80
+ const result: {
81
+ isBatched: boolean;
82
+ data: {
83
+ fromAddressAndType: AddressAndType;
84
+ stateMachinePayload:
85
+ | StaticDecode<CommandTuple<string, typeof nep171Grammar>>
86
+ | null;
87
+ accountingPayload: JsonObject;
88
+ }[];
89
+ } = {
90
+ isBatched: tokenIds.length > 1,
91
+ data: [],
92
+ };
93
+
94
+ for (const tokenId of tokenIds) {
95
+ const accountingPayload: ParamToData<typeof nep171Grammar> = {
96
+ old_owner_id: oldOwnerId,
97
+ new_owner_id: newOwnerId,
98
+ token_id: tokenId,
99
+ isBurn,
100
+ };
101
+
102
+ const stateMachinePayload: StaticDecode<
103
+ CommandTuple<string, typeof nep171Grammar>
104
+ > | null = this.stateMachinePrefix
105
+ ? generateRawStmInput(
106
+ this.grammar,
107
+ this.stateMachinePrefix,
108
+ accountingPayload,
109
+ )
110
+ : null;
111
+
112
+ result.data.push({
113
+ fromAddressAndType: {
114
+ type: AddressType.NEAR,
115
+ address: oldOwnerId,
116
+ },
117
+ accountingPayload,
118
+ stateMachinePayload,
119
+ });
120
+ }
121
+
122
+ return result;
123
+ }
124
+
125
+ override getConfig(): ProtocolPrimitiveMap[
126
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
127
+ ] {
128
+ return {
129
+ name: this.instanceName,
130
+ type: this.internalTypeName,
131
+ startBlockHeight: this.startBlockHeight,
132
+ contractId: this.contractId,
133
+ eventStandard: "nep171",
134
+ eventType: "nft_transfer",
135
+ scheduledPrefix: this.stateMachinePrefix,
136
+ };
137
+ }
138
+ }
@@ -0,0 +1,11 @@
1
+ import { Type } from "@sinclair/typebox";
2
+
3
+ export const nep245Grammar = [
4
+ ['type', Type.String()],
5
+ ['old_owner_id', Type.String()],
6
+ ['new_owner_id', Type.String()],
7
+ ['token_id', Type.String()],
8
+ ['amount', Type.String()],
9
+ ['isMint', Type.Boolean()],
10
+ ['isBurn', Type.Boolean()],
11
+ ] as const;
@@ -0,0 +1,84 @@
1
+ import { PrimitiveTypeNEARNEP245 } from "../builtin.ts";
2
+
3
+ export function nep245Ivm(name: string) {
4
+ const lowerName = name.toLowerCase();
5
+ const validSQLName = lowerName.replace(/[^a-zA-Z0-9_]/g, "");
6
+ if (validSQLName !== lowerName) {
7
+ throw new Error(`Invalid name: ${name}`);
8
+ }
9
+
10
+ const balanceTable = `primitives.nep245_balance_intermediate_${validSQLName}`;
11
+
12
+ return `
13
+ CREATE TABLE IF NOT EXISTS ${balanceTable} (
14
+ primitive_name TEXT NOT NULL,
15
+ token_id TEXT NOT NULL,
16
+ account_id TEXT NOT NULL,
17
+ amount numeric(78,0) DEFAULT 0,
18
+ last_transfer_block_height INTEGER NOT NULL DEFAULT 0,
19
+ last_transfer_id INTEGER NOT NULL DEFAULT 0,
20
+ PRIMARY KEY (primitive_name, token_id, account_id)
21
+ );
22
+
23
+ CREATE OR REPLACE FUNCTION update_nep245_balance_${validSQLName}() RETURNS TRIGGER AS $$
24
+ DECLARE
25
+ transfer_amount numeric(78,0);
26
+ from_account TEXT;
27
+ to_account TEXT;
28
+ mt_token_id TEXT;
29
+ is_mint BOOLEAN;
30
+ is_burn BOOLEAN;
31
+ BEGIN
32
+ IF NEW.payload_type = '${PrimitiveTypeNEARNEP245}'
33
+ AND NEW.primitive_name = '${name}'
34
+ AND NEW.payload->>'amount' IS NOT NULL THEN
35
+
36
+ transfer_amount := (NEW.payload->>'amount')::numeric(78,0);
37
+ from_account := NEW.payload->>'old_owner_id';
38
+ to_account := NEW.payload->>'new_owner_id';
39
+ mt_token_id := NEW.payload->>'token_id';
40
+ is_mint := COALESCE((NEW.payload->>'isMint')::boolean, false);
41
+ is_burn := COALESCE((NEW.payload->>'isBurn')::boolean, false);
42
+
43
+ IF from_account IS NOT NULL AND from_account != '' AND NOT is_mint THEN
44
+ INSERT INTO ${balanceTable} (primitive_name, token_id, account_id, amount, last_transfer_block_height, last_transfer_id)
45
+ VALUES (NEW.primitive_name, mt_token_id, from_account, -transfer_amount, NEW.effectstream_block_height, NEW.id)
46
+ ON CONFLICT (primitive_name, token_id, account_id) DO UPDATE SET
47
+ amount = ${balanceTable}.amount - transfer_amount,
48
+ last_transfer_block_height = NEW.effectstream_block_height,
49
+ last_transfer_id = NEW.id;
50
+ END IF;
51
+
52
+ IF to_account IS NOT NULL AND to_account != '' AND NOT is_burn THEN
53
+ INSERT INTO ${balanceTable} (primitive_name, token_id, account_id, amount, last_transfer_block_height, last_transfer_id)
54
+ VALUES (NEW.primitive_name, mt_token_id, to_account, transfer_amount, NEW.effectstream_block_height, NEW.id)
55
+ ON CONFLICT (primitive_name, token_id, account_id) DO UPDATE SET
56
+ amount = ${balanceTable}.amount + transfer_amount,
57
+ last_transfer_block_height = NEW.effectstream_block_height,
58
+ last_transfer_id = NEW.id;
59
+ END IF;
60
+ END IF;
61
+
62
+ RETURN NEW;
63
+ END;
64
+ $$ LANGUAGE plpgsql;
65
+
66
+ CREATE TRIGGER trigger_update_nep245_balance_${validSQLName}
67
+ AFTER INSERT ON effectstream.primitive_accounting
68
+ FOR EACH ROW
69
+ EXECUTE FUNCTION update_nep245_balance_${validSQLName}();
70
+
71
+ SELECT pgivm.create_immv('primitives.nep245_balance_view_${validSQLName}',
72
+ 'SELECT
73
+ primitive_name,
74
+ token_id,
75
+ account_id,
76
+ amount
77
+ FROM ${balanceTable}
78
+ WHERE amount > 0;
79
+ ');
80
+ `;
81
+ }
82
+
83
+ export const NEP245_VIEW_PREFIX = "nep245_balance_view_" as const;
84
+ export const NEP245_INTERMEDIATE_PREFIX = "nep245_balance_intermediate_" as const;
@@ -0,0 +1,147 @@
1
+ import type { StaticDecode } from "@sinclair/typebox";
2
+ import {
3
+ type ConfigSyncProtocolType,
4
+ type FlattenSyncProtocolIOFor,
5
+ type ProtocolPrimitiveMap,
6
+ } from "@effectstream/config";
7
+ import {
8
+ type AddressAndType,
9
+ AddressType,
10
+ type EffectstreamBlockNumber,
11
+ } from "@effectstream/utils";
12
+ import { type JsonObject, Primitive } from "@effectstream/sm";
13
+ import {
14
+ type CommandTuple,
15
+ generateRawStmInput,
16
+ type ParamToData,
17
+ } from "@effectstream/concise";
18
+ import type { StateUpdateStream } from "@effectstream/coroutine";
19
+ import { nep245Grammar } from "./nep245-grammar.ts";
20
+ import {
21
+ NEP245_INTERMEDIATE_PREFIX,
22
+ NEP245_VIEW_PREFIX,
23
+ nep245Ivm,
24
+ } from "./nep245-ivm.ts";
25
+ import { PrimitiveTypeNEARNEP245 } from "../builtin.ts";
26
+
27
+ const ZERO_ACCOUNT = "";
28
+
29
+ export class Nep245Primitive extends Primitive<
30
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL,
31
+ typeof nep245Grammar
32
+ > {
33
+ readonly internalTypeName = PrimitiveTypeNEARNEP245;
34
+ override grammar = nep245Grammar;
35
+ readonly contractId: string;
36
+
37
+ override dynamicTables = nep245Ivm;
38
+ override getIntermediatePrefix(): string[] {
39
+ return [NEP245_INTERMEDIATE_PREFIX];
40
+ }
41
+ override getViewPrefix(): string[] {
42
+ return [NEP245_VIEW_PREFIX];
43
+ }
44
+
45
+ constructor(config: {
46
+ instanceName: string;
47
+ startBlockHeight: number;
48
+ contractId: string;
49
+ stateMachinePrefix: string | undefined;
50
+ }) {
51
+ super(config);
52
+ this.contractId = config.contractId;
53
+ }
54
+
55
+ override *getPayload(
56
+ _: EffectstreamBlockNumber,
57
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
58
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
59
+ >,
60
+ ): StateUpdateStream<{
61
+ isBatched: boolean;
62
+ data: {
63
+ fromAddressAndType: AddressAndType;
64
+ stateMachinePayload:
65
+ | StaticDecode<CommandTuple<string, typeof nep245Grammar>>
66
+ | null;
67
+ accountingPayload: JsonObject;
68
+ }[];
69
+ }> {
70
+ const payload = primitiveTransactionData.output.payload as Record<string, unknown>;
71
+ const eventType = String(payload._event ?? "mt_transfer");
72
+ const oldOwnerId = String(payload.old_owner_id ?? "");
73
+ const newOwnerId = String(payload.new_owner_id ?? "");
74
+
75
+ // NEP-245 events have parallel token_ids[] and amounts[]
76
+ const tokenIds: string[] = Array.isArray(payload.token_ids)
77
+ ? (payload.token_ids as string[])
78
+ : [String(payload.token_ids ?? payload.token_id ?? "")];
79
+ const amounts: string[] = Array.isArray(payload.amounts)
80
+ ? (payload.amounts as string[])
81
+ : [String(payload.amounts ?? payload.amount ?? "0")];
82
+
83
+ const isMint = oldOwnerId === ZERO_ACCOUNT || eventType === "mt_mint";
84
+ const isBurn = newOwnerId === ZERO_ACCOUNT || eventType === "mt_burn";
85
+
86
+ const result: {
87
+ isBatched: boolean;
88
+ data: {
89
+ fromAddressAndType: AddressAndType;
90
+ stateMachinePayload:
91
+ | StaticDecode<CommandTuple<string, typeof nep245Grammar>>
92
+ | null;
93
+ accountingPayload: JsonObject;
94
+ }[];
95
+ } = {
96
+ isBatched: tokenIds.length > 1,
97
+ data: [],
98
+ };
99
+
100
+ for (let i = 0; i < tokenIds.length; i++) {
101
+ const accountingPayload: ParamToData<typeof nep245Grammar> = {
102
+ type: eventType,
103
+ old_owner_id: oldOwnerId,
104
+ new_owner_id: newOwnerId,
105
+ token_id: tokenIds[i],
106
+ amount: amounts[i] ?? "0",
107
+ isMint,
108
+ isBurn,
109
+ };
110
+
111
+ const stateMachinePayload: StaticDecode<
112
+ CommandTuple<string, typeof nep245Grammar>
113
+ > | null = this.stateMachinePrefix
114
+ ? generateRawStmInput(
115
+ this.grammar,
116
+ this.stateMachinePrefix,
117
+ accountingPayload,
118
+ )
119
+ : null;
120
+
121
+ result.data.push({
122
+ fromAddressAndType: {
123
+ type: AddressType.NEAR,
124
+ address: oldOwnerId || newOwnerId,
125
+ },
126
+ accountingPayload,
127
+ stateMachinePayload,
128
+ });
129
+ }
130
+
131
+ return result;
132
+ }
133
+
134
+ override getConfig(): ProtocolPrimitiveMap[
135
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
136
+ ] {
137
+ return {
138
+ name: this.instanceName,
139
+ type: this.internalTypeName,
140
+ startBlockHeight: this.startBlockHeight,
141
+ contractId: this.contractId,
142
+ eventStandard: "nep245",
143
+ eventType: "mt_transfer",
144
+ scheduledPrefix: this.stateMachinePrefix,
145
+ };
146
+ }
147
+ }
@@ -0,0 +1,6 @@
1
+ import { Type } from '@sinclair/typebox';
2
+
3
+ export const utxorpcGenericGrammar = [
4
+ ["hash", Type.String()],
5
+ ["bytes", Type.String()],
6
+ ] as const;
@@ -0,0 +1,88 @@
1
+ import type { Static, StaticDecode, TSchema } from '@sinclair/typebox';
2
+ import {
3
+ type CommandTuple,
4
+ generateRawStmInput,
5
+ type ParamToData,
6
+ } from "@effectstream/concise";
7
+ import type { ConfigSyncProtocolType, FlattenSyncProtocolIOFor, ProtocolPrimitiveMap, UtxorpcTxPredicate } from '@effectstream/config';
8
+ import type { StateUpdateStream } from "@effectstream/coroutine";
9
+ import { type JsonObject, Primitive } from "@effectstream/sm";
10
+ import { type AddressAndType, AddressType, type EffectstreamBlockNumber, uint8ArrayToHexString } from '@effectstream/utils';
11
+ import { utxorpcGenericGrammar } from './utxorpc-generic-grammar.ts';
12
+ import { PrimitiveTypeUtxorpcGeneric } from '../builtin.ts';
13
+
14
+ export class UtxorpcGenericPrimitive extends Primitive<
15
+ ConfigSyncProtocolType.CARDANO_UTXORPC_PARALLEL,
16
+ typeof utxorpcGenericGrammar
17
+ > {
18
+ readonly internalTypeName = PrimitiveTypeUtxorpcGeneric;
19
+ readonly predicate: UtxorpcTxPredicate;
20
+ override grammar = utxorpcGenericGrammar;
21
+
22
+ constructor(config: {
23
+ instanceName: string;
24
+ startBlockHeight: number;
25
+ stateMachinePrefix: string | undefined;
26
+ predicate: UtxorpcTxPredicate;
27
+ }) {
28
+ super(config);
29
+ this.predicate = config.predicate;
30
+ }
31
+
32
+ override getConfig(): ProtocolPrimitiveMap[
33
+ ConfigSyncProtocolType.CARDANO_UTXORPC_PARALLEL
34
+ ] {
35
+ return {
36
+ name: this.instanceName,
37
+ type: this.internalTypeName,
38
+ startBlockHeight: this.startBlockHeight,
39
+ scheduledPrefix: this.stateMachinePrefix,
40
+ predicate: this.predicate,
41
+ } as const;
42
+ }
43
+
44
+ override *getPayload(
45
+ _: EffectstreamBlockNumber,
46
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
47
+ ConfigSyncProtocolType.CARDANO_UTXORPC_PARALLEL
48
+ >,
49
+ ): StateUpdateStream<{
50
+ isBatched: boolean;
51
+ data: {
52
+ fromAddressAndType: AddressAndType;
53
+ stateMachinePayload:
54
+ | StaticDecode<
55
+ CommandTuple<string, typeof utxorpcGenericGrammar>
56
+ >
57
+ | null;
58
+ accountingPayload: JsonObject;
59
+ }[];
60
+ }> {
61
+ const payload = primitiveTransactionData.output.payload;
62
+ const accountingPayload = {
63
+ hash: uint8ArrayToHexString(payload.tx.hash),
64
+ bytes: uint8ArrayToHexString(payload.tx.toBinary()),
65
+ };
66
+ const stateMachinePayload: any = this.stateMachinePrefix
67
+ ? generateRawStmInput(
68
+ this.grammar,
69
+ this.stateMachinePrefix,
70
+ accountingPayload,
71
+ )
72
+ : null;
73
+
74
+ return {
75
+ isBatched: false,
76
+ data: [
77
+ {
78
+ fromAddressAndType: {
79
+ type: AddressType.NONE,
80
+ address: "0x0",
81
+ },
82
+ accountingPayload,
83
+ stateMachinePayload,
84
+ },
85
+ ],
86
+ };
87
+ }
88
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Valid JSON Object, required for the db accounting.
3
+ */
4
+ export type JsonValue =
5
+ | string
6
+ | number
7
+ | boolean
8
+ | null
9
+ | JsonValue[]
10
+ | { [key: string]: JsonValue };
11
+
12
+ export type JsonObject = {
13
+ [key: string]: JsonValue;
14
+ };