Skip to content

Commit

Permalink
erc721 cde: keep track of the address that burned the asset (#323)
Browse files Browse the repository at this point in the history
* erc721 cde: keep track of the address that burnt the asset

* track the dead address too

* add optional burn prefix and scheduled data

* burn events: don't schedule data on presync
  • Loading branch information
ecioppettini authored Apr 5, 2024
1 parent dbac191 commit 6c0af96
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 5 deletions.
1 change: 1 addition & 0 deletions packages/engine/paima-funnel/src/cde/erc721.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function transferToTransferDatum(
to: event.returnValues.to.toLowerCase(),
tokenId: event.returnValues.tokenId,
},
burnScheduledPrefix: extension.burnScheduledPrefix,
network,
};
}
Expand Down
35 changes: 31 additions & 4 deletions packages/engine/paima-sm/src/cde-erc721-transfer.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import type { PoolClient } from 'pg';

import { doLog } from '@paima/utils';
import { doLog, ENV } from '@paima/utils';
import type { CdeErc721TransferDatum } from './types.js';
import { cdeErc721GetOwner, cdeErc721InsertOwner, cdeErc721UpdateOwner } from '@paima/db';
import {
cdeErc721BurnInsert,
cdeErc721Delete,
cdeErc721GetOwner,
cdeErc721InsertOwner,
cdeErc721UpdateOwner,
createScheduledData,
} from '@paima/db';
import type { SQLUpdate } from '@paima/db';

export default async function processErc721Datum(
readonlyDBConn: PoolClient,
cdeDatum: CdeErc721TransferDatum
cdeDatum: CdeErc721TransferDatum,
isPresync: boolean
): Promise<SQLUpdate[]> {
const cdeId = cdeDatum.cdeId;
const { to, tokenId } = cdeDatum.payload;
const toAddr = to.toLowerCase();

const isBurn = Boolean(toAddr.toLocaleLowerCase().match(/^0x0+(dead)?$/g));

const updateList: SQLUpdate[] = [];
try {
const ownerRow = await cdeErc721GetOwner.run(
Expand All @@ -21,7 +31,24 @@ export default async function processErc721Datum(
);
const newOwnerData = { cde_id: cdeId, token_id: tokenId, nft_owner: toAddr };
if (ownerRow.length > 0) {
updateList.push([cdeErc721UpdateOwner, newOwnerData]);
if (isBurn) {
if (cdeDatum.burnScheduledPrefix && !isPresync) {
const scheduledInputData = `${cdeDatum.burnScheduledPrefix}|${ownerRow[0].nft_owner}|${tokenId}`;
const scheduledBlockHeight = cdeDatum.blockNumber;

updateList.push(createScheduledData(scheduledInputData, scheduledBlockHeight));
}

// we do this to keep track of the owner before the asset is sent to the
// burn address
updateList.push([
cdeErc721BurnInsert,
{ cde_id: cdeId, token_id: tokenId, nft_owner: ownerRow[0].nft_owner },
]);
updateList.push([cdeErc721Delete, { cde_id: cdeId, token_id: tokenId }]);
} else {
updateList.push([cdeErc721UpdateOwner, newOwnerData]);
}
} else {
updateList.push([cdeErc721InsertOwner, newOwnerData]);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/paima-sm/src/cde-processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export async function cdeTransitionFunction(
case ChainDataExtensionDatumType.ERC20Transfer:
return await processErc20TransferDatum(readonlyDBConn, cdeDatum);
case ChainDataExtensionDatumType.ERC721Transfer:
return await processErc721TransferDatum(readonlyDBConn, cdeDatum);
return await processErc721TransferDatum(readonlyDBConn, cdeDatum, inPresync);
case ChainDataExtensionDatumType.ERC721Mint:
return await processErc721MintDatum(cdeDatum, inPresync);
case ChainDataExtensionDatumType.ERC20Deposit:
Expand Down
2 changes: 2 additions & 0 deletions packages/engine/paima-sm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export interface CdeErc20TransferDatum extends CdeDatumBase {
export interface CdeErc721TransferDatum extends CdeDatumBase {
cdeDatumType: ChainDataExtensionDatumType.ERC721Transfer;
payload: CdeDatumErc721TransferPayload;
burnScheduledPrefix?: string | undefined;
}

export interface CdeErc721MintDatum extends CdeDatumBase {
Expand Down Expand Up @@ -287,6 +288,7 @@ export const ChainDataExtensionErc721Config = Type.Intersect([
type: Type.Literal(CdeEntryTypeName.ERC721),
contractAddress: EvmAddress,
scheduledPrefix: Type.String(),
burnScheduledPrefix: Type.Optional(Type.String()),
}),
]);
export type TChainDataExtensionErc721Config = Static<typeof ChainDataExtensionErc721Config>;
Expand Down
7 changes: 7 additions & 0 deletions packages/node-sdk/paima-db/migrations/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ CREATE TABLE cde_erc721_data (
PRIMARY KEY (cde_id, token_id)
);

CREATE TABLE cde_erc721_burn (
cde_id INTEGER NOT NULL,
token_id TEXT NOT NULL,
nft_owner TEXT NOT NULL,
PRIMARY KEY(cde_id, token_id)
);

CREATE TABLE cde_erc20_deposit_data (
cde_id INTEGER NOT NULL,
wallet_address TEXT NOT NULL,
Expand Down
22 changes: 22 additions & 0 deletions packages/node-sdk/paima-db/src/paima-tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,27 @@ const TABLE_DATA_CDE_ERC721: TableData = {
creationQuery: QUERY_CREATE_TABLE_CDE_ERC721,
};

const QUERY_CREATE_TABLE_CDE_ERC721_BURN = `
CREATE TABLE cde_erc721_burn (
cde_id INTEGER NOT NULL,
token_id TEXT NOT NULL,
nft_owner TEXT NOT NULL,
PRIMARY KEY (cde_id, token_id)
);
`;

const TABLE_DATA_CDE_ERC721_BURN: TableData = {
tableName: 'cde_erc721_data_burn',
primaryKeyColumns: ['cde_id', 'token_id'],
columnData: packTuples([
['cde_id', 'integer', 'NO', ''],
['token_id', 'text', 'NO', ''],
['nft_owner', 'text', 'NO', ''],
]),
serialColumns: [],
creationQuery: QUERY_CREATE_TABLE_CDE_ERC721_BURN,
};

const QUERY_CREATE_TABLE_CDE_ERC20_DEPOSIT = `
CREATE TABLE cde_erc20_deposit_data (
cde_id INTEGER NOT NULL,
Expand Down Expand Up @@ -580,6 +601,7 @@ export const TABLES: TableData[] = [
TABLE_DATA_CDE,
TABLE_DATA_CDE_ERC20,
TABLE_DATA_CDE_ERC721,
TABLE_DATA_CDE_ERC721_BURN,
TABLE_DATA_CDE_ERC20_DEPOSIT,
TABLE_DATA_CDE_GENERIC_DATA,
TABLE_DATA_CDE_ERC6551_REGISTRY,
Expand Down
63 changes: 63 additions & 0 deletions packages/node-sdk/paima-db/src/sql/cde-erc721.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,66 @@ const cdeErc721GetAllOwnedNftsIR: any = {"usedParamSet":{"nft_owner":true},"para
export const cdeErc721GetAllOwnedNfts = new PreparedQuery<ICdeErc721GetAllOwnedNftsParams,ICdeErc721GetAllOwnedNftsResult>(cdeErc721GetAllOwnedNftsIR);


/** 'CdeErc721Delete' parameters type */
export interface ICdeErc721DeleteParams {
cde_id: number;
token_id: string;
}

/** 'CdeErc721Delete' return type */
export type ICdeErc721DeleteResult = void;

/** 'CdeErc721Delete' query type */
export interface ICdeErc721DeleteQuery {
params: ICdeErc721DeleteParams;
result: ICdeErc721DeleteResult;
}

const cdeErc721DeleteIR: any = {"usedParamSet":{"cde_id":true,"token_id":true},"params":[{"name":"cde_id","required":true,"transform":{"type":"scalar"},"locs":[{"a":43,"b":50}]},{"name":"token_id","required":true,"transform":{"type":"scalar"},"locs":[{"a":67,"b":76}]}],"statement":"DELETE FROM cde_erc721_data\nWHERE cde_id = :cde_id!\nAND token_id = :token_id!"};

/**
* Query generated from SQL:
* ```
* DELETE FROM cde_erc721_data
* WHERE cde_id = :cde_id!
* AND token_id = :token_id!
* ```
*/
export const cdeErc721Delete = new PreparedQuery<ICdeErc721DeleteParams,ICdeErc721DeleteResult>(cdeErc721DeleteIR);


/** 'CdeErc721BurnInsert' parameters type */
export interface ICdeErc721BurnInsertParams {
cde_id: number;
nft_owner: string;
token_id: string;
}

/** 'CdeErc721BurnInsert' return type */
export type ICdeErc721BurnInsertResult = void;

/** 'CdeErc721BurnInsert' query type */
export interface ICdeErc721BurnInsertQuery {
params: ICdeErc721BurnInsertParams;
result: ICdeErc721BurnInsertResult;
}

const cdeErc721BurnInsertIR: any = {"usedParamSet":{"cde_id":true,"token_id":true,"nft_owner":true},"params":[{"name":"cde_id","required":true,"transform":{"type":"scalar"},"locs":[{"a":84,"b":91}]},{"name":"token_id","required":true,"transform":{"type":"scalar"},"locs":[{"a":98,"b":107}]},{"name":"nft_owner","required":true,"transform":{"type":"scalar"},"locs":[{"a":114,"b":124}]}],"statement":"INSERT INTO cde_erc721_burn(\n cde_id,\n token_id,\n nft_owner\n) VALUES (\n :cde_id!,\n :token_id!,\n :nft_owner!\n)"};

/**
* Query generated from SQL:
* ```
* INSERT INTO cde_erc721_burn(
* cde_id,
* token_id,
* nft_owner
* ) VALUES (
* :cde_id!,
* :token_id!,
* :nft_owner!
* )
* ```
*/
export const cdeErc721BurnInsert = new PreparedQuery<ICdeErc721BurnInsertParams,ICdeErc721BurnInsertResult>(cdeErc721BurnInsertIR);


17 changes: 17 additions & 0 deletions packages/node-sdk/paima-db/src/sql/cde-erc721.sql
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,20 @@ AND token_id = :token_id!;
SELECT cde_name, token_id FROM cde_erc721_data
JOIN chain_data_extensions ON chain_data_extensions.cde_id = cde_erc721_data.cde_id
WHERE nft_owner = :nft_owner!;


/* @name cdeErc721Delete */
DELETE FROM cde_erc721_data
WHERE cde_id = :cde_id!
AND token_id = :token_id!;

/* @name cdeErc721BurnInsert */
INSERT INTO cde_erc721_burn(
cde_id,
token_id,
nft_owner
) VALUES (
:cde_id!,
:token_id!,
:nft_owner!
);

0 comments on commit 6c0af96

Please sign in to comment.