Skip to content

Commit d59e747

Browse files
committed
feat(persistence-ethereum): Added support for erc1155
Signed-off-by: Harshdev098 <[email protected]>
1 parent 1ba7bd9 commit d59e747

File tree

11 files changed

+1791
-33
lines changed

11 files changed

+1791
-33
lines changed

packages/cactus-plugin-persistence-ethereum/src/main/json/contract-abi/ERC1155.json

Lines changed: 579 additions & 0 deletions
Large diffs are not rendered by default.

packages/cactus-plugin-persistence-ethereum/src/main/json/openapi.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
"schemas": {
1414
"TokenTypeV1": {
1515
"type": "string",
16-
"enum": ["erc20", "erc721"],
16+
"enum": ["erc20", "erc721","erc1155"],
1717
"x-enum-descriptions": [
1818
"EIP-20: Token Standard",
19-
"EIP-721: Non-Fungible Token Standard"
19+
"EIP-721: Non-Fungible Token Standard",
20+
"EIP-1155: Multi Token Standard"
2021
],
21-
"x-enum-varnames": ["ERC20", "ERC721"]
22+
"x-enum-varnames": ["ERC20", "ERC721","ERC1155"]
2223
},
2324
"MonitoredToken": {
2425
"description": "Ethereum tokens that are being monitored by the persistence plugin.",

packages/cactus-plugin-persistence-ethereum/src/main/sql/schema.sql

Lines changed: 212 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,87 @@ CREATE POLICY token_metadata_erc721_delete ON ethereum."token_metadata_erc721"
147147
FOR DELETE TO anon, authenticated, service_role
148148
USING (true);
149149

150+
-- Table: ethereum.token_metadata_erc1155
151+
152+
-- DROP TABLE IF EXISTS ethereum.token_metadata_erc1155;
153+
154+
CREATE TABLE IF NOT EXISTS ethereum.token_metadata_erc1155
155+
(
156+
address text COLLATE pg_catalog."default" NOT NULL,
157+
name text COLLATE pg_catalog."default",
158+
symbol text COLLATE pg_catalog."default",
159+
created_at timestamp with time zone NOT NULL DEFAULT now(),
160+
CONSTRAINT token_metadata_erc1155_pkey PRIMARY KEY (address),
161+
CONSTRAINT token_metadata_erc1155_address_key UNIQUE (address)
162+
);
163+
164+
ALTER TABLE IF EXISTS ethereum.token_metadata_erc1155
165+
OWNER to postgres;
166+
167+
ALTER TABLE ethereum.token_metadata_erc1155
168+
ENABLE ROW LEVEL SECURITY;
169+
170+
CREATE POLICY token_metadata_erc1155_select ON ethereum.token_metadata_erc1155
171+
FOR SELECT TO anon, authenticated, service_role
172+
USING (true);
173+
174+
CREATE POLICY token_metadata_erc1155_insert ON ethereum.token_metadata_erc1155
175+
FOR INSERT TO anon, authenticated, service_role
176+
WITH CHECK (true);
177+
178+
CREATE POLICY token_metadata_erc1155_update ON ethereum.token_metadata_erc1155
179+
FOR UPDATE TO anon, authenticated, service_role
180+
USING (true)
181+
WITH CHECK (true);
182+
183+
CREATE POLICY token_metadata_erc1155_delete ON ethereum.token_metadata_erc1155
184+
FOR DELETE TO anon, authenticated, service_role
185+
USING (true);
186+
187+
-- Table: ethereum.token_erc1155
188+
189+
-- DROP TABLE IF EXISTS ethereum.token_erc1155;
190+
191+
CREATE TABLE IF NOT EXISTS ethereum.token_erc1155
192+
(
193+
id uuid DEFAULT uuid_generate_v4() NOT NULL,
194+
account_address text COLLATE pg_catalog."default" NOT NULL,
195+
token_address text COLLATE pg_catalog."default" NOT NULL,
196+
token_id numeric NOT NULL,
197+
balance numeric NOT NULL DEFAULT 0,
198+
uri text COLLATE pg_catalog."default",
199+
last_balance_change timestamp without time zone NOT NULL DEFAULT now(),
200+
CONSTRAINT token_erc1155_pkey PRIMARY KEY (id),
201+
CONSTRAINT token_erc1155_contract_token_account_unique UNIQUE (token_address, token_id, account_address),
202+
CONSTRAINT token_erc1155_token_address_fkey FOREIGN KEY (token_address)
203+
REFERENCES ethereum.token_metadata_erc1155 (address) MATCH SIMPLE
204+
ON UPDATE NO ACTION
205+
ON DELETE NO ACTION
206+
);
207+
208+
ALTER TABLE IF EXISTS ethereum.token_erc1155
209+
OWNER to postgres;
210+
211+
ALTER TABLE ethereum.token_erc1155
212+
ENABLE ROW LEVEL SECURITY;
213+
214+
CREATE POLICY token_erc1155_select ON ethereum.token_erc1155
215+
FOR SELECT TO anon, authenticated, service_role
216+
USING (true);
217+
218+
CREATE POLICY token_erc1155_insert ON ethereum.token_erc1155
219+
FOR INSERT TO anon, authenticated, service_role
220+
WITH CHECK (true);
221+
222+
CREATE POLICY token_erc1155_update ON ethereum.token_erc1155
223+
FOR UPDATE TO anon, authenticated, service_role
224+
USING (true)
225+
WITH CHECK (true);
226+
227+
CREATE POLICY token_erc1155_delete ON ethereum.token_erc1155
228+
FOR DELETE TO anon, authenticated, service_role
229+
USING (true);
230+
150231
-- Table: ethereum.token_erc721
151232

152233
-- DROP TABLE IF EXISTS ethereum.token_erc721;
@@ -277,8 +358,15 @@ CREATE POLICY token_transfer_delete ON ethereum.token_transfer
277358
FOR DELETE TO anon, authenticated, service_role
278359
USING (true);
279360

361+
-- Adding token_id column to token_transfer for ERC-1155 support
362+
ALTER TABLE ethereum.token_transfer
363+
ADD COLUMN IF NOT EXISTS token_id numeric;
364+
280365
COMMENT ON COLUMN ethereum.token_transfer.value
281-
IS 'ERC20 - token quantity, ERC721 - token ID';
366+
IS 'ERC20 - token quantity, ERC721 - not used (see token_id), ERC1155 - token quantity';
367+
368+
COMMENT ON COLUMN ethereum.token_transfer.token_id
369+
IS 'ERC721 - token ID, ERC1155 - token ID, ERC20 - not used';
282370

283371
----------------------------------------------------------------------------------------------------
284372
-- VIEWS
@@ -329,6 +417,31 @@ WITH (security_invoker = on)
329417
ALTER TABLE ethereum.erc721_token_history_view
330418
OWNER TO postgres;
331419

420+
-- View: ethereum.erc1155_token_history_view
421+
422+
-- DROP VIEW IF EXISTS ethereum.erc1155_token_history_view;
423+
424+
CREATE OR REPLACE VIEW ethereum.erc1155_token_history_view
425+
WITH (security_invoker = on)
426+
AS
427+
SELECT
428+
tx.hash AS transaction_hash,
429+
tx."to" AS token_address,
430+
b.created_at,
431+
tt.sender,
432+
tt.recipient,
433+
tt.token_id,
434+
tt.value AS quantity
435+
FROM ethereum.transaction tx
436+
JOIN ethereum.block b ON tx.block_number = b.number
437+
JOIN ethereum.token_transfer tt ON tx.id = tt.transaction_id
438+
JOIN ethereum.token_metadata_erc1155 tkn ON tx."to" = tkn.address
439+
WHERE tt.token_id IS NOT NULL -- Ensure token_id is present (ERC-1155 or ERC-721)
440+
ORDER BY b.created_at, tt.recipient;
441+
442+
ALTER TABLE ethereum.erc1155_token_history_view
443+
OWNER TO postgres;
444+
332445
-- View: ethereum.token_erc20
333446

334447
-- DROP MATERIALIZED VIEW IF EXISTS ethereum.token_erc20;
@@ -460,6 +573,104 @@ ALTER PROCEDURE ethereum.update_issued_erc721_tokens(numeric)
460573

461574
GRANT EXECUTE ON PROCEDURE ethereum.update_issued_erc721_tokens(numeric) TO public;
462575

576+
-- PROCEDURE: ethereum.update_issued_erc1155_tokens(numeric)
577+
578+
-- DROP PROCEDURE IF EXISTS ethereum.update_issued_erc1155_tokens(numeric);
579+
580+
CREATE OR REPLACE PROCEDURE ethereum.update_issued_erc1155_tokens(IN from_block_number numeric)
581+
LANGUAGE 'plpgsql'
582+
SET search_path = ethereum, public
583+
AS $BODY$
584+
DECLARE
585+
current_token_entry ethereum.token_erc1155%ROWTYPE;
586+
token_transfer record;
587+
block_created_at timestamp;
588+
BEGIN
589+
-- Get the block's creation time
590+
SELECT created_at
591+
FROM ethereum.block
592+
WHERE number = from_block_number
593+
INTO block_created_at;
594+
595+
IF NOT found THEN
596+
raise exception 'invalid block provided: %', from_block_number
597+
USING hint = 'ensure that given block was synchronized correctly';
598+
END IF;
599+
600+
-- Process each transfer (distinct by token_address, token_id, recipient to handle batch transfers)
601+
FOR token_transfer IN SELECT
602+
*
603+
FROM ethereum.erc1155_token_history_view
604+
WHERE created_at >= block_created_at
605+
ORDER BY token_address, token_id, sender, recipient, created_at DESC
606+
LOOP
607+
-- Process sender (decrease balance)
608+
IF token_transfer.sender != '0x0000000000000000000000000000000000000000' THEN -- Not a mint
609+
SELECT * FROM ethereum.token_erc1155
610+
WHERE token_id = token_transfer.token_id
611+
AND token_address = token_transfer.token_address
612+
AND account_address = token_transfer.sender
613+
INTO current_token_entry;
614+
615+
IF found THEN
616+
-- Decrease sender's balance
617+
UPDATE ethereum.token_erc1155
618+
SET balance = GREATEST(0, balance - token_transfer.quantity),
619+
last_balance_change = token_transfer.created_at
620+
WHERE id = current_token_entry.id;
621+
622+
-- Remove entry if balance reaches 0
623+
DELETE FROM ethereum.token_erc1155
624+
WHERE id = current_token_entry.id AND balance = 0;
625+
END IF;
626+
END IF;
627+
628+
-- Process recipient (increase balance)
629+
IF token_transfer.recipient != '0x0000000000000000000000000000000000000000' THEN -- Not a burn
630+
SELECT * FROM ethereum.token_erc1155
631+
WHERE token_id = token_transfer.token_id
632+
AND token_address = token_transfer.token_address
633+
AND account_address = token_transfer.recipient
634+
INTO current_token_entry;
635+
636+
IF NOT found THEN
637+
-- Create new entry for recipient
638+
raise notice 'create entry for token ID % on contract % for account %',
639+
token_transfer.token_id, token_transfer.token_address, token_transfer.recipient;
640+
INSERT INTO ethereum.token_erc1155
641+
VALUES (
642+
uuid_generate_v4(),
643+
token_transfer.recipient,
644+
token_transfer.token_address,
645+
token_transfer.token_id,
646+
token_transfer.quantity,
647+
NULL, -- uri (can be fetched later)
648+
token_transfer.created_at
649+
);
650+
ELSE
651+
-- Increase recipient's balance
652+
IF current_token_entry.last_balance_change < token_transfer.created_at THEN
653+
raise notice 'update balance for token ID % on contract % for account %',
654+
token_transfer.token_id, token_transfer.token_address, token_transfer.recipient;
655+
UPDATE ethereum.token_erc1155
656+
SET balance = balance + token_transfer.quantity,
657+
last_balance_change = token_transfer.created_at
658+
WHERE id = current_token_entry.id;
659+
ELSE
660+
raise notice 'current entry is more recent - ignore token ID % on contract % for account %',
661+
token_transfer.token_id, token_transfer.token_address, token_transfer.recipient;
662+
END IF;
663+
END IF;
664+
END IF;
665+
END LOOP;
666+
END
667+
$BODY$;
668+
669+
ALTER PROCEDURE ethereum.update_issued_erc1155_tokens(numeric)
670+
OWNER TO postgres;
671+
672+
GRANT EXECUTE ON PROCEDURE ethereum.update_issued_erc1155_tokens(numeric) TO public;
673+
463674
-- FUNCTION: ethereum.get_missing_blocks_in_range(integer, integer)
464675

465676
-- DROP FUNCTION IF EXISTS ethereum.get_missing_blocks_in_range(integer, integer);

packages/cactus-plugin-persistence-ethereum/src/main/typescript/db-client/database.types.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,35 @@ export interface Database {
8181
last_owner_change?: string;
8282
};
8383
};
84+
token_erc1155: {
85+
Row: {
86+
id: string;
87+
account_address: string;
88+
token_address: string;
89+
token_id: number;
90+
balance: number;
91+
uri: string | null;
92+
last_balance_change: string;
93+
};
94+
Insert: {
95+
id?: string;
96+
account_address: string;
97+
token_address: string;
98+
token_id: number;
99+
balance: number;
100+
uri?: string | null;
101+
last_balance_change?: string;
102+
};
103+
Update: {
104+
id?: string;
105+
account_address?: string;
106+
token_address?: string;
107+
token_id?: number;
108+
balance: number;
109+
uri?: string | null;
110+
last_balance_change?: string;
111+
}
112+
}
84113
token_metadata_erc20: {
85114
Row: {
86115
address: string;
@@ -124,6 +153,26 @@ export interface Database {
124153
created_at?: string;
125154
};
126155
};
156+
token_metadata_erc1155: {
157+
Row: {
158+
address: string;
159+
name: string | null;
160+
symbol: string | null;
161+
created_at: string;
162+
};
163+
Insert: {
164+
address: string;
165+
name: string | null;
166+
symbol: string | null;
167+
created_at?: string;
168+
};
169+
Update: {
170+
address?: string;
171+
name?: string | null;
172+
symbol?: string | null;
173+
created_at?: string;
174+
}
175+
}
127176
token_transfer: {
128177
Row: {
129178
transaction_id: string;

0 commit comments

Comments
 (0)