@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,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,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,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
|
+
}
|