@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,81 @@
1
+ import {
2
+ PrimitiveTypeMidnightGeneric,
3
+ PrimitiveTypeMidnightNullifier,
4
+ PrimitiveTypeEVMEffectstreamL2,
5
+ PrimitiveTypeEVMERC721,
6
+ PrimitiveTypeEVMERC20,
7
+ PrimitiveTypeAvailGeneric,
8
+ PrimitiveTypeEVMERC1155,
9
+ PrimitiveTypeBitcoinAddress,
10
+ PrimitiveTypeUtxorpcGeneric,
11
+ PrimitiveTypeCelestiaGeneric,
12
+ PrimitiveTypeNEARNEP141,
13
+ PrimitiveTypeNEARNEP171,
14
+ PrimitiveTypeNEARNEP245,
15
+ PrimitiveTypeNEARIntent,
16
+ PrimitiveTypeNEARGeneric,
17
+ PrimitiveTypeNEARAccountWatch,
18
+ // PrimitiveTypeEVMGeneric,
19
+ } from "./builtin.ts";
20
+
21
+ import { MidnightGenericPrimitive } from "./midnight-generic/midnight-genetic.ts";
22
+ import { MidnightNullifierPrimitive } from "./midnight-nullifier/midnight-nullifier.ts";
23
+ import { EffectstreamL2Primitive } from "./evm-effectstream-l2/effectstream-l2-primitive.ts";
24
+ import { Erc721Primitive } from "./evm-erc721/erc721-primitive.ts";
25
+ import { Erc20Primitive } from "./evm-erc20/erc20-primitive.ts";
26
+ import { AvailGenericPrimitive } from "./avail-generic/avail-primitive.ts";
27
+ import { Erc1155Primitive } from "./evm-erc1155/erc1155-primitive.ts";
28
+ import { BitcoinAddressPrimitive } from "./bitcoin-address/bitcoin-primitive.ts";
29
+ import { UtxorpcGenericPrimitive } from "./utxorpc-generic/utxorpc-generic.ts";
30
+ import { CelestiaGenericPrimitive } from "./celestia-generic/celestia-primitive.ts";
31
+ import { Nep141Primitive } from "./near-nep141/nep141-primitive.ts";
32
+ import { Nep171Primitive } from "./near-nep171/nep171-primitive.ts";
33
+ import { Nep245Primitive } from "./near-nep245/nep245-primitive.ts";
34
+ import { NearIntentPrimitive } from "./near-intent/near-intent-primitive.ts";
35
+ import { NearGenericPrimitive } from "./near-generic/near-generic-primitive.ts";
36
+ import { NearAccountWatchPrimitive } from "./near-account-watch/near-account-watch-primitive.ts";
37
+ // import { EvmGenericPrimitive } from "./evm-generic/evm-generic-primitive.ts";
38
+
39
+ const builtInPrimitivesMap = {
40
+ [PrimitiveTypeMidnightGeneric]: MidnightGenericPrimitive,
41
+ [PrimitiveTypeMidnightNullifier]: MidnightNullifierPrimitive,
42
+ [PrimitiveTypeEVMEffectstreamL2]: EffectstreamL2Primitive,
43
+ [PrimitiveTypeEVMERC721]: Erc721Primitive,
44
+ [PrimitiveTypeEVMERC20]: Erc20Primitive,
45
+ [PrimitiveTypeAvailGeneric]: AvailGenericPrimitive,
46
+ [PrimitiveTypeEVMERC1155]: Erc1155Primitive,
47
+ [PrimitiveTypeBitcoinAddress]: BitcoinAddressPrimitive,
48
+ [PrimitiveTypeUtxorpcGeneric]: UtxorpcGenericPrimitive,
49
+ [PrimitiveTypeCelestiaGeneric]: CelestiaGenericPrimitive,
50
+ [PrimitiveTypeNEARNEP141]: Nep141Primitive,
51
+ [PrimitiveTypeNEARNEP171]: Nep171Primitive,
52
+ [PrimitiveTypeNEARNEP245]: Nep245Primitive,
53
+ [PrimitiveTypeNEARIntent]: NearIntentPrimitive,
54
+ [PrimitiveTypeNEARGeneric]: NearGenericPrimitive,
55
+ [PrimitiveTypeNEARAccountWatch]: NearAccountWatchPrimitive,
56
+ // [PrimitiveTypeEVMGeneric]: EvmGenericPrimitive,
57
+ } as const;
58
+
59
+ export {
60
+ // Built-in Primitives Map
61
+ builtInPrimitivesMap,
62
+
63
+ // Built-in Primitives
64
+ MidnightGenericPrimitive,
65
+ MidnightNullifierPrimitive,
66
+ EffectstreamL2Primitive,
67
+ Erc721Primitive,
68
+ Erc20Primitive,
69
+ AvailGenericPrimitive,
70
+ Erc1155Primitive,
71
+ BitcoinAddressPrimitive,
72
+ UtxorpcGenericPrimitive,
73
+ CelestiaGenericPrimitive,
74
+ Nep141Primitive,
75
+ Nep171Primitive,
76
+ Nep245Primitive,
77
+ NearIntentPrimitive,
78
+ NearGenericPrimitive,
79
+ NearAccountWatchPrimitive,
80
+ // EvmGenericPrimitive,
81
+ };
@@ -0,0 +1,10 @@
1
+ import { Type } from "@sinclair/typebox";
2
+
3
+ export const nearAccountWatchGrammar = [
4
+ ['signer_id', Type.String()],
5
+ ['receiver_id', Type.String()],
6
+ ['method_name', Type.String()],
7
+ ['args', Type.String()],
8
+ ['deposit', Type.String()],
9
+ ['status', Type.String()],
10
+ ] as const;
@@ -0,0 +1,106 @@
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 { nearAccountWatchGrammar } from "./near-account-watch-grammar.ts";
20
+ import { PrimitiveTypeNEARAccountWatch } from "../builtin.ts";
21
+
22
+ export class NearAccountWatchPrimitive extends Primitive<
23
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL,
24
+ typeof nearAccountWatchGrammar
25
+ > {
26
+ readonly internalTypeName = PrimitiveTypeNEARAccountWatch;
27
+ override grammar = nearAccountWatchGrammar;
28
+ readonly contractId: string;
29
+
30
+ constructor(config: {
31
+ instanceName: string;
32
+ startBlockHeight: number;
33
+ contractId: string;
34
+ stateMachinePrefix: string | undefined;
35
+ }) {
36
+ super(config);
37
+ this.contractId = config.contractId;
38
+ }
39
+
40
+ override *getPayload(
41
+ _: EffectstreamBlockNumber,
42
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
43
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
44
+ >,
45
+ ): StateUpdateStream<{
46
+ isBatched: boolean;
47
+ data: {
48
+ fromAddressAndType: AddressAndType;
49
+ stateMachinePayload:
50
+ | StaticDecode<CommandTuple<string, typeof nearAccountWatchGrammar>>
51
+ | null;
52
+ accountingPayload: JsonObject;
53
+ }[];
54
+ }> {
55
+ const payload = primitiveTransactionData.output.payload as Record<string, unknown>;
56
+ const signerId = String(payload.signer_id ?? "");
57
+ const receiverId = String(payload.receiver_id ?? "");
58
+ const methodName = String(payload.method_name ?? "");
59
+ const args = String(payload.args ?? "");
60
+ const deposit = String(payload.deposit ?? "0");
61
+ const status = String(payload.status ?? "unknown");
62
+
63
+ const accountingPayload: ParamToData<typeof nearAccountWatchGrammar> = {
64
+ signer_id: signerId,
65
+ receiver_id: receiverId,
66
+ method_name: methodName,
67
+ args,
68
+ deposit,
69
+ status,
70
+ };
71
+
72
+ const stateMachinePayload = this.stateMachinePrefix
73
+ ? generateRawStmInput(
74
+ this.grammar,
75
+ this.stateMachinePrefix,
76
+ accountingPayload,
77
+ )
78
+ : null;
79
+
80
+ return {
81
+ isBatched: false,
82
+ data: [
83
+ {
84
+ fromAddressAndType: {
85
+ type: AddressType.NEAR,
86
+ address: signerId,
87
+ },
88
+ accountingPayload,
89
+ stateMachinePayload,
90
+ },
91
+ ],
92
+ };
93
+ }
94
+
95
+ override getConfig(): ProtocolPrimitiveMap[
96
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
97
+ ] {
98
+ return {
99
+ name: this.instanceName,
100
+ type: this.internalTypeName,
101
+ startBlockHeight: this.startBlockHeight,
102
+ contractId: this.contractId,
103
+ scheduledPrefix: this.stateMachinePrefix,
104
+ };
105
+ }
106
+ }
@@ -0,0 +1,5 @@
1
+ import { Type } from "@sinclair/typebox";
2
+
3
+ export const nearGenericGrammar = [
4
+ ['payload', Type.Any()],
5
+ ] as const;
@@ -0,0 +1,105 @@
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 { nearGenericGrammar } from "./near-generic-grammar.ts";
20
+ import { PrimitiveTypeNEARGeneric } from "../builtin.ts";
21
+
22
+ export class NearGenericPrimitive extends Primitive<
23
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL,
24
+ typeof nearGenericGrammar
25
+ > {
26
+ readonly internalTypeName = PrimitiveTypeNEARGeneric;
27
+ override grammar = nearGenericGrammar;
28
+ readonly contractId: string;
29
+ readonly eventStandard: string;
30
+ readonly eventType: string;
31
+
32
+ constructor(config: {
33
+ instanceName: string;
34
+ startBlockHeight: number;
35
+ contractId: string;
36
+ eventStandard: string;
37
+ eventType: string;
38
+ stateMachinePrefix: string | undefined;
39
+ }) {
40
+ super(config);
41
+ this.contractId = config.contractId;
42
+ this.eventStandard = config.eventStandard;
43
+ this.eventType = config.eventType;
44
+ }
45
+
46
+ override *getPayload(
47
+ _: EffectstreamBlockNumber,
48
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
49
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
50
+ >,
51
+ ): StateUpdateStream<{
52
+ isBatched: boolean;
53
+ data: {
54
+ fromAddressAndType: AddressAndType;
55
+ stateMachinePayload:
56
+ | StaticDecode<CommandTuple<string, typeof nearGenericGrammar>>
57
+ | null;
58
+ accountingPayload: JsonObject;
59
+ }[];
60
+ }> {
61
+ const payload = primitiveTransactionData.output.payload;
62
+
63
+ const accountingPayload: ParamToData<typeof nearGenericGrammar> = {
64
+ payload,
65
+ };
66
+
67
+ const stateMachinePayload = this.stateMachinePrefix
68
+ ? generateRawStmInput(
69
+ this.grammar,
70
+ this.stateMachinePrefix,
71
+ accountingPayload,
72
+ )
73
+ : null;
74
+
75
+ return {
76
+ isBatched: false,
77
+ data: [
78
+ {
79
+ fromAddressAndType: {
80
+ type: AddressType.NEAR,
81
+ address: String(
82
+ primitiveTransactionData.syncProtocol.contractAddress ?? "",
83
+ ),
84
+ },
85
+ accountingPayload,
86
+ stateMachinePayload,
87
+ },
88
+ ],
89
+ };
90
+ }
91
+
92
+ override getConfig(): ProtocolPrimitiveMap[
93
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
94
+ ] {
95
+ return {
96
+ name: this.instanceName,
97
+ type: this.internalTypeName,
98
+ startBlockHeight: this.startBlockHeight,
99
+ contractId: this.contractId,
100
+ eventStandard: this.eventStandard,
101
+ eventType: this.eventType,
102
+ scheduledPrefix: this.stateMachinePrefix,
103
+ };
104
+ }
105
+ }
@@ -0,0 +1,10 @@
1
+ import { Type } from "@sinclair/typebox";
2
+
3
+ export const nearIntentGrammar = [
4
+ ['account_id', Type.String()],
5
+ ['intent_hash', Type.String()],
6
+ ['token_diffs', Type.Array(Type.Object({
7
+ token_id: Type.String(),
8
+ amount: Type.String(),
9
+ }))],
10
+ ] as const;
@@ -0,0 +1,71 @@
1
+ import { PrimitiveTypeNEARIntent } from "../builtin.ts";
2
+
3
+ export function nearIntentIvm(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 settlementTable = `primitives.near_intent_settlement_intermediate_${validSQLName}`;
11
+
12
+ return `
13
+ CREATE TABLE IF NOT EXISTS ${settlementTable} (
14
+ primitive_name TEXT NOT NULL,
15
+ intent_hash TEXT NOT NULL,
16
+ account_id TEXT NOT NULL,
17
+ token_id TEXT NOT NULL,
18
+ amount numeric(78,0) DEFAULT 0,
19
+ block_height INTEGER NOT NULL DEFAULT 0,
20
+ PRIMARY KEY (primitive_name, intent_hash, account_id, token_id)
21
+ );
22
+
23
+ CREATE OR REPLACE FUNCTION update_near_intent_settlement_${validSQLName}() RETURNS TRIGGER AS $$
24
+ DECLARE
25
+ diff_item JSONB;
26
+ BEGIN
27
+ IF NEW.payload_type = '${PrimitiveTypeNEARIntent}'
28
+ AND NEW.primitive_name = '${name}'
29
+ AND (NEW.payload::jsonb)->'token_diffs' IS NOT NULL THEN
30
+
31
+ FOR diff_item IN SELECT * FROM jsonb_array_elements((NEW.payload::jsonb)->'token_diffs')
32
+ LOOP
33
+ INSERT INTO ${settlementTable} (primitive_name, intent_hash, account_id, token_id, amount, block_height)
34
+ VALUES (
35
+ NEW.primitive_name,
36
+ (NEW.payload::jsonb)->>'intent_hash',
37
+ (NEW.payload::jsonb)->>'account_id',
38
+ diff_item->>'token_id',
39
+ (diff_item->>'amount')::numeric(78,0),
40
+ NEW.effectstream_block_height
41
+ )
42
+ ON CONFLICT (primitive_name, intent_hash, account_id, token_id) DO UPDATE SET
43
+ amount = (diff_item->>'amount')::numeric(78,0),
44
+ block_height = NEW.effectstream_block_height;
45
+ END LOOP;
46
+ END IF;
47
+
48
+ RETURN NEW;
49
+ END;
50
+ $$ LANGUAGE plpgsql;
51
+
52
+ CREATE TRIGGER trigger_update_near_intent_settlement_${validSQLName}
53
+ AFTER INSERT ON effectstream.primitive_accounting
54
+ FOR EACH ROW
55
+ EXECUTE FUNCTION update_near_intent_settlement_${validSQLName}();
56
+
57
+ SELECT pgivm.create_immv('primitives.near_intent_settlement_view_${validSQLName}',
58
+ 'SELECT
59
+ primitive_name,
60
+ intent_hash,
61
+ account_id,
62
+ token_id,
63
+ amount,
64
+ block_height
65
+ FROM ${settlementTable};
66
+ ');
67
+ `;
68
+ }
69
+
70
+ export const NEAR_INTENT_VIEW_PREFIX = "near_intent_settlement_view_" as const;
71
+ export const NEAR_INTENT_INTERMEDIATE_PREFIX = "near_intent_settlement_intermediate_" as const;
@@ -0,0 +1,149 @@
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 { nearIntentGrammar } from "./near-intent-grammar.ts";
20
+ import {
21
+ NEAR_INTENT_INTERMEDIATE_PREFIX,
22
+ NEAR_INTENT_VIEW_PREFIX,
23
+ nearIntentIvm,
24
+ } from "./near-intent-ivm.ts";
25
+ import { PrimitiveTypeNEARIntent } from "../builtin.ts";
26
+ import { matchesGlob } from "./near-intent-token-id-parser.ts";
27
+
28
+ export class NearIntentPrimitive extends Primitive<
29
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL,
30
+ typeof nearIntentGrammar
31
+ > {
32
+ readonly internalTypeName = PrimitiveTypeNEARIntent;
33
+ override grammar = nearIntentGrammar;
34
+ readonly contractId: string;
35
+ readonly filterTokenIds: string[];
36
+ readonly filterAccountIds: string[];
37
+
38
+ override dynamicTables = nearIntentIvm;
39
+ override getIntermediatePrefix(): string[] {
40
+ return [NEAR_INTENT_INTERMEDIATE_PREFIX];
41
+ }
42
+ override getViewPrefix(): string[] {
43
+ return [NEAR_INTENT_VIEW_PREFIX];
44
+ }
45
+
46
+ constructor(config: {
47
+ instanceName: string;
48
+ startBlockHeight: number;
49
+ contractId: string;
50
+ stateMachinePrefix: string | undefined;
51
+ filterTokenIds?: string[];
52
+ filterAccountIds?: string[];
53
+ }) {
54
+ super(config);
55
+ this.contractId = config.contractId;
56
+ this.filterTokenIds = config.filterTokenIds ?? [];
57
+ this.filterAccountIds = config.filterAccountIds ?? [];
58
+ }
59
+
60
+ override *getPayload(
61
+ _: EffectstreamBlockNumber,
62
+ primitiveTransactionData: FlattenSyncProtocolIOFor<
63
+ ConfigSyncProtocolType.NEAR_RPC_PARALLEL
64
+ >,
65
+ ): StateUpdateStream<{
66
+ isBatched: boolean;
67
+ data: {
68
+ fromAddressAndType: AddressAndType;
69
+ stateMachinePayload:
70
+ | StaticDecode<CommandTuple<string, typeof nearIntentGrammar>>
71
+ | null;
72
+ accountingPayload: JsonObject;
73
+ }[];
74
+ }> {
75
+ const payload = primitiveTransactionData.output.payload as Record<string, unknown>;
76
+ const accountId = String(payload.account_id ?? "");
77
+ const intentHash = String(payload.intent_hash ?? "");
78
+
79
+ // Apply account filter
80
+ if (
81
+ this.filterAccountIds.length > 0 &&
82
+ !this.filterAccountIds.some((p) => matchesGlob(p, accountId))
83
+ ) {
84
+ return { isBatched: false, data: [] };
85
+ }
86
+
87
+ // Parse DIP-4 diff object into token_diffs array
88
+ const diff = (payload.diff ?? {}) as Record<string, string>;
89
+ const tokenDiffs: { token_id: string; amount: string }[] = [];
90
+ for (const [tokenId, amount] of Object.entries(diff)) {
91
+ // Apply token filter
92
+ if (
93
+ this.filterTokenIds.length > 0 &&
94
+ !this.filterTokenIds.some((p) => matchesGlob(p, tokenId))
95
+ ) {
96
+ continue;
97
+ }
98
+ tokenDiffs.push({ token_id: tokenId, amount: String(amount) });
99
+ }
100
+
101
+ if (tokenDiffs.length === 0) {
102
+ return { isBatched: false, data: [] };
103
+ }
104
+
105
+ const accountingPayload: ParamToData<typeof nearIntentGrammar> = {
106
+ account_id: accountId,
107
+ intent_hash: intentHash,
108
+ token_diffs: tokenDiffs,
109
+ };
110
+
111
+ const stateMachinePayload = this.stateMachinePrefix
112
+ ? generateRawStmInput(
113
+ this.grammar,
114
+ this.stateMachinePrefix,
115
+ accountingPayload,
116
+ )
117
+ : null;
118
+
119
+ return {
120
+ isBatched: false,
121
+ data: [
122
+ {
123
+ fromAddressAndType: {
124
+ type: AddressType.NEAR,
125
+ address: accountId,
126
+ },
127
+ accountingPayload,
128
+ stateMachinePayload,
129
+ },
130
+ ],
131
+ };
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: "dip4",
143
+ eventType: "token_diff",
144
+ filterTokenIds: this.filterTokenIds,
145
+ filterAccountIds: this.filterAccountIds,
146
+ scheduledPrefix: this.stateMachinePrefix,
147
+ };
148
+ }
149
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Parses a NEAR Intents Verifier namespaced token ID.
3
+ *
4
+ * Token IDs follow the format: `standard:contract[:localId]`
5
+ * Examples:
6
+ * "nep141:wrap.near" → { standard: "nep141", contract: "wrap.near", localId: null }
7
+ * "nep171:nft.near:token42" → { standard: "nep171", contract: "nft.near", localId: "token42" }
8
+ * "nep245:game.near:sword" → { standard: "nep245", contract: "game.near", localId: "sword" }
9
+ */
10
+ export type ParsedTokenId = {
11
+ standard: string;
12
+ contract: string;
13
+ localId: string | null;
14
+ };
15
+
16
+ export function parseIntentTokenId(tokenId: string): ParsedTokenId {
17
+ const firstColon = tokenId.indexOf(":");
18
+ if (firstColon === -1) {
19
+ return { standard: "unknown", contract: tokenId, localId: null };
20
+ }
21
+
22
+ const standard = tokenId.slice(0, firstColon);
23
+ const rest = tokenId.slice(firstColon + 1);
24
+
25
+ const secondColon = rest.indexOf(":");
26
+ if (secondColon === -1) {
27
+ return { standard, contract: rest, localId: null };
28
+ }
29
+
30
+ return {
31
+ standard,
32
+ contract: rest.slice(0, secondColon),
33
+ localId: rest.slice(secondColon + 1),
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Simple glob matcher supporting `*` (matches any characters except `.`)
39
+ * and `**` or trailing `*` (matches everything).
40
+ */
41
+ export function matchesGlob(pattern: string, value: string): boolean {
42
+ const regex = pattern
43
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
44
+ .replace(/\*\*/g, ".*")
45
+ .replace(/\*/g, "[^.]*");
46
+ return new RegExp(`^${regex}$`).test(value);
47
+ }
@@ -0,0 +1,7 @@
1
+ import { Type } from "@sinclair/typebox";
2
+
3
+ export const nep141Grammar = [
4
+ ['old_owner_id', Type.String()],
5
+ ['new_owner_id', Type.String()],
6
+ ['amount', Type.String()],
7
+ ] as const;
@@ -0,0 +1,70 @@
1
+ import { PrimitiveTypeNEARNEP141 } from "../builtin.ts";
2
+
3
+ export function nep141Ivm(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.nep141_balance_intermediate_${validSQLName}`;
11
+
12
+ return `
13
+ CREATE TABLE IF NOT EXISTS ${balanceTable} (
14
+ primitive_name TEXT NOT NULL,
15
+ account_id TEXT NOT NULL,
16
+ balance numeric(78,0) DEFAULT 0,
17
+ PRIMARY KEY (primitive_name, account_id)
18
+ );
19
+
20
+ CREATE OR REPLACE FUNCTION update_nep141_balance_${validSQLName}() RETURNS TRIGGER AS $$
21
+ DECLARE
22
+ transfer_amount numeric(78,0);
23
+ from_account TEXT;
24
+ to_account TEXT;
25
+ BEGIN
26
+ IF NEW.payload_type = '${PrimitiveTypeNEARNEP141}'
27
+ AND NEW.primitive_name = '${name}'
28
+ AND NEW.payload->>'amount' IS NOT NULL THEN
29
+
30
+ transfer_amount := (NEW.payload->>'amount')::numeric(78,0);
31
+ from_account := NEW.payload->>'old_owner_id';
32
+ to_account := NEW.payload->>'new_owner_id';
33
+
34
+ IF from_account IS NOT NULL AND from_account != '' THEN
35
+ INSERT INTO ${balanceTable} (primitive_name, account_id, balance)
36
+ VALUES (NEW.primitive_name, from_account, -transfer_amount)
37
+ ON CONFLICT (primitive_name, account_id) DO UPDATE SET
38
+ balance = ${balanceTable}.balance - transfer_amount;
39
+ END IF;
40
+
41
+ IF to_account IS NOT NULL AND to_account != '' THEN
42
+ INSERT INTO ${balanceTable} (primitive_name, account_id, balance)
43
+ VALUES (NEW.primitive_name, to_account, transfer_amount)
44
+ ON CONFLICT (primitive_name, account_id) DO UPDATE SET
45
+ balance = ${balanceTable}.balance + transfer_amount;
46
+ END IF;
47
+ END IF;
48
+
49
+ RETURN NEW;
50
+ END;
51
+ $$ LANGUAGE plpgsql;
52
+
53
+ CREATE TRIGGER trigger_update_nep141_balance_${validSQLName}
54
+ AFTER INSERT ON effectstream.primitive_accounting
55
+ FOR EACH ROW
56
+ EXECUTE FUNCTION update_nep141_balance_${validSQLName}();
57
+
58
+ SELECT pgivm.create_immv('primitives.nep141_balance_view_${validSQLName}',
59
+ 'SELECT
60
+ primitive_name,
61
+ account_id,
62
+ balance
63
+ FROM ${balanceTable}
64
+ WHERE balance > 0;
65
+ ');
66
+ `;
67
+ }
68
+
69
+ export const NEP141_VIEW_PREFIX = "nep141_balance_view_" as const;
70
+ export const NEP141_INTERMEDIATE_PREFIX = "nep141_balance_intermediate_" as const;