Skip to content

Commit

Permalink
cardano mint and burn cde (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
ecioppettini committed Mar 5, 2024
1 parent b922ca9 commit 1b8c768
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 1 deletion.
92 changes: 92 additions & 0 deletions packages/engine/paima-funnel/src/cde/cardanoMintBurn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type {
CdeCardanoMintBurnDatum,
CdeCardanoTransferDatum,
ChainDataExtensionCardanoMintBurn,
ChainDataExtensionCardanoTransfer,
} from '@paima/sm';
import { ChainDataExtensionDatumType, DEFAULT_FUNNEL_TIMEOUT, timeout } from '@paima/utils';
import { Routes, query } from '@dcspark/carp-client/client/src';
import type { TxAndBlockInfo } from '@dcspark/carp-client/shared/models/TransactionHistory';
import { Transaction } from '@dcspark/cardano-multiplatform-lib-nodejs';
import { BlockTxPair } from '@dcspark/carp-client/shared/models/common';
import { MintBurnHistoryResponse } from 'tmp-carp-client/shared/models/MintBurn';

export default async function getCdeData(
url: string,
extension: ChainDataExtensionCardanoMintBurn,
fromAbsoluteSlot: number,
toAbsoluteSlot: number,
getBlockNumber: (slot: number) => number,
// if we are in the presync phase, we don't care about the slots since we
// don't need to deterministically pair this with the evm blocks, so in this
// case we only fetch one page and break.
isPresync: boolean,
untilBlock: string,
// only should be used during the presync phase, to be able to resume from the
// previous point
fromTx: BlockTxPair | undefined,
paginationLimit: number
): Promise<CdeCardanoMintBurnDatum[]> {
let result = [] as CdeCardanoMintBurnDatum[];

while (true) {
const events = await timeout(
query(url, Routes.mintBurnHistory, {
policyIds: extension.policyIds,
slotLimits: {
from: fromAbsoluteSlot,
to: toAbsoluteSlot,
},
limit: paginationLimit,
untilBlock,
after: fromTx,
}),
DEFAULT_FUNNEL_TIMEOUT
);

if (events.length > 0) {
const last = events[events.length - 1];

fromTx = {
tx: last.txId,
block: last.block,
};
}

events
.map(e => eventToCdeDatum(e, extension, getBlockNumber(e.actionSlot)))
.forEach(element => {
result.push(element);
});

if (events.length === 0 || isPresync) {
break;
}
}

return result;
}

function eventToCdeDatum(
event: MintBurnHistoryResponse[0],
extension: ChainDataExtensionCardanoMintBurn,
blockNumber: number
): CdeCardanoMintBurnDatum {
const cursor: BlockTxPair = {
block: event.block,
tx: event.txId,
};

return {
cdeId: extension.cdeId,
cdeDatumType: ChainDataExtensionDatumType.CardanoMintBurn,
blockNumber,
payload: {
txId: event.txId,
metadata: event.metadata,
assets: event.assets,
},
scheduledPrefix: extension.scheduledPrefix,
paginationCursor: { cursor: JSON.stringify(cursor), finished: false },
};
}
1 change: 1 addition & 0 deletions packages/engine/paima-funnel/src/cde/reading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ async function getSpecificCdeData(
case ChainDataExtensionType.CardanoProjectedNFT:
case ChainDataExtensionType.CardanoAssetUtxo:
case ChainDataExtensionType.CardanoTransfer:
case ChainDataExtensionType.CardanoMintBurn:
// this is used by the block funnel, which can't get information for this
// extension
return [];
Expand Down
39 changes: 39 additions & 0 deletions packages/engine/paima-funnel/src/funnels/carp/funnel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import getCdePoolData from '../../cde/cardanoPool.js';
import getCdeProjectedNFTData from '../../cde/cardanoProjectedNFT.js';
import getCdeDelayedAsset from '../../cde/delayedAsset.js';
import getCdeTransferData from '../../cde/cardanoTransfer.js';
import getCdeMintBurnData from '../../cde/cardanoMintBurn.js';
import { query } from '@dcspark/carp-client/client/src/index';
import { Routes } from '@dcspark/carp-client/shared/routes';
import { FUNNEL_PRESYNC_FINISHED, InternalEventType } from '@paima/utils';
Expand Down Expand Up @@ -361,6 +362,30 @@ export class CarpFunnel extends BaseFunnel implements ChainFunnel {
data,
}));
}
case ChainDataExtensionType.CardanoMintBurn: {
const cursors = this.cache.getState().cursors;
const startingSlot = this.cache.getState().startingSlot - 1;

const cursor = cursors && cursors[extension.cdeId];

const data = getCdeMintBurnData(
this.carpUrl,
extension,
extension.startSlot,
Math.min(startingSlot, extension.stopSlot || startingSlot),
slot => slot,
true,
stableBlock.block.hash,
cursor ? (JSON.parse(cursor.cursor) as BlockTxPair) : undefined,
this.config.paginationLimit
).then(mapCursorPaginatedData(extension.cdeId));

return data.then(data => ({
cdeId: extension.cdeId,
cdeType: extension.cdeType,
data,
}));
}
default:
throw new Error(`[carp funnel] unhandled extension: ${extension.cdeType}`);
}
Expand Down Expand Up @@ -574,6 +599,20 @@ async function readDataInternal(
);

return transferData;
case ChainDataExtensionType.CardanoMintBurn:
const mintBurnData = getCdeMintBurnData(
carpUrl,
extension,
min,
Math.min(max, extension.stopSlot || max),
mapSlotToBlockNumber,
false, // not presync
stableBlockId,
undefined, // we want everything in the range, so no starting point for the pagination
paginationLimit
);

return mintBurnData;
default:
return Promise.resolve([]);
}
Expand Down
18 changes: 18 additions & 0 deletions packages/engine/paima-runtime/src/cde-config/loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
CdeEntryTypeName,
ChainDataExtensionCardanoDelayedAssetConfig,
ChainDataExtensionCardanoDelegationConfig,
ChainDataExtensionCardanoMintBurnConfig,
ChainDataExtensionCardanoProjectedNFTConfig,
ChainDataExtensionCardanoTransferConfig,
ChainDataExtensionErc20Config,
Expand Down Expand Up @@ -141,6 +142,15 @@ export function parseCdeConfigFile(configFileData: string): Static<typeof CdeCon
]),
entry
);
case CdeEntryTypeName.CardanoMintBurn:
return checkOrError(
entry.name,
Type.Intersect([
ChainDataExtensionCardanoMintBurnConfig,
Type.Object({ network: Type.String() }),
]),
entry
);
default:
assertNever(entry.type);
}
Expand Down Expand Up @@ -289,6 +299,14 @@ async function instantiateExtension(
hash: hashConfig(config),
cdeType: ChainDataExtensionType.CardanoTransfer,
};
case CdeEntryTypeName.CardanoMintBurn:
return {
...config,
network: config.network || defaultCardanoNetworkName,
cdeId: index,
hash: hashConfig(config),
cdeType: ChainDataExtensionType.CardanoMintBurn,
};
default:
assertNever(config);
}
Expand Down
21 changes: 21 additions & 0 deletions packages/engine/paima-sm/src/cde-cardano-mint-burn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ENV } from '@paima/utils';
import { createScheduledData } from '@paima/db';
import type { SQLUpdate } from '@paima/db';
import type { CdeCardanoMintBurnDatum } from './types.js';

export default async function processDatum(
cdeDatum: CdeCardanoMintBurnDatum
): Promise<SQLUpdate[]> {
const cdeId = cdeDatum.cdeId;
const prefix = cdeDatum.scheduledPrefix;
const txId = cdeDatum.payload.txId;
const assets = JSON.stringify(cdeDatum.payload.assets);
const metadata = cdeDatum.payload.metadata || undefined;

const scheduledBlockHeight = Math.max(cdeDatum.blockNumber, ENV.SM_START_BLOCKHEIGHT + 1);
const scheduledInputData = `${prefix}|${txId}|${metadata}|${assets}`;

// TODO: do we really need to always store something in the db? In this case I'm not sure what would be queried.
const updateList: SQLUpdate[] = [createScheduledData(scheduledInputData, scheduledBlockHeight)];
return updateList;
}
3 changes: 3 additions & 0 deletions packages/engine/paima-sm/src/cde-processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import processCardanoDelegationDatum from './cde-cardano-pool.js';
import processCardanoProjectedNFT from './cde-cardano-projected-nft.js';
import processCardanoAssetUtxoDatum from './cde-cardano-delayed-asset.js';
import processCardanoTransferDatum from './cde-cardano-transfer.js';
import processCardanoMintBurnDatum from './cde-cardano-mint-burn.js';
import assertNever from 'assert-never';
import type { SQLUpdate } from '@paima/db';

Expand Down Expand Up @@ -41,6 +42,8 @@ export async function cdeTransitionFunction(
return await processCardanoAssetUtxoDatum(cdeDatum);
case ChainDataExtensionDatumType.CardanoTransfer:
return await processCardanoTransferDatum(cdeDatum);
case ChainDataExtensionDatumType.CardanoMintBurn:
return await processCardanoMintBurnDatum(cdeDatum);
default:
assertNever(cdeDatum);
}
Expand Down
33 changes: 32 additions & 1 deletion packages/engine/paima-sm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ interface CdeDatumCardanoTransferPayload {
metadata: string | null;
}

interface CdeDatumCardanoMintBurnPayload {
txId: string;
metadata: string | null;
assets: { [policyId: string]: { [assetName: string]: string } };
}

type ChainDataExtensionPayload =
| CdeDatumErc20TransferPayload
| CdeDatumErc721MintPayload
Expand Down Expand Up @@ -209,6 +215,13 @@ export interface CdeCardanoTransferDatum extends CdeDatumBase {
paginationCursor: { cursor: string; finished: boolean };
}

export interface CdeCardanoMintBurnDatum extends CdeDatumBase {
cdeDatumType: ChainDataExtensionDatumType.CardanoMintBurn;
payload: CdeDatumCardanoMintBurnPayload;
scheduledPrefix: string | undefined;
paginationCursor: { cursor: string; finished: boolean };
}

export type ChainDataExtensionDatum =
| CdeErc20TransferDatum
| CdeErc721MintDatum
Expand All @@ -219,7 +232,8 @@ export type ChainDataExtensionDatum =
| CdeCardanoPoolDatum
| CdeCardanoProjectedNFTDatum
| CdeCardanoAssetUtxoDatum
| CdeCardanoTransferDatum;
| CdeCardanoTransferDatum
| CdeCardanoMintBurnDatum;

export enum CdeEntryTypeName {
Generic = 'generic',
Expand All @@ -231,6 +245,7 @@ export enum CdeEntryTypeName {
CardanoProjectedNFT = 'cardano-projected-nft',
CardanoDelayedAsset = 'cardano-delayed-asset',
CardanoTransfer = 'cardano-transfer',
CardanoMintBurn = 'cardano-mint-burn',
}

const EvmAddress = Type.Transform(Type.RegExp('0x[0-9a-fA-F]{40}'))
Expand Down Expand Up @@ -390,6 +405,20 @@ export type ChainDataExtensionCardanoTransfer = ChainDataExtensionBase &
cdeType: ChainDataExtensionType.CardanoTransfer;
};

export const ChainDataExtensionCardanoMintBurnConfig = Type.Object({
type: Type.Literal(CdeEntryTypeName.CardanoMintBurn),
policyIds: Type.Array(Type.String()),
scheduledPrefix: Type.String(),
startSlot: Type.Number(),
stopSlot: Type.Optional(Type.Number()),
name: Type.String(),
});

export type ChainDataExtensionCardanoMintBurn = ChainDataExtensionBase &
Static<typeof ChainDataExtensionCardanoMintBurnConfig> & {
cdeType: ChainDataExtensionType.CardanoMintBurn;
};

export const CdeConfig = Type.Object({
extensions: Type.Array(
Type.Intersect([
Expand All @@ -403,6 +432,7 @@ export const CdeConfig = Type.Object({
ChainDataExtensionCardanoProjectedNFTConfig,
ChainDataExtensionCardanoDelayedAssetConfig,
ChainDataExtensionCardanoTransferConfig,
ChainDataExtensionCardanoMintBurnConfig,
]),
Type.Partial(Type.Object({ network: Type.String() })),
])
Expand Down Expand Up @@ -433,6 +463,7 @@ export type ChainDataExtension = (
| ChainDataExtensionCardanoProjectedNFT
| ChainDataExtensionCardanoDelayedAsset
| ChainDataExtensionCardanoTransfer
| ChainDataExtensionCardanoMintBurn
) & { network: string | undefined };

export type GameStateTransitionFunctionRouter = (
Expand Down
2 changes: 2 additions & 0 deletions packages/paima-sdk/paima-utils/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const enum ChainDataExtensionType {
CardanoProjectedNFT = 8,
CardanoAssetUtxo = 9,
CardanoTransfer = 10,
CardanoMintBurn = 11,
}

export const enum ChainDataExtensionDatumType {
Expand All @@ -35,6 +36,7 @@ export const enum ChainDataExtensionDatumType {
CardanoProjectedNFT,
CardanoAssetUtxo,
CardanoTransfer,
CardanoMintBurn,
}

export const FUNNEL_PRESYNC_FINISHED = 'finished';
Expand Down

0 comments on commit 1b8c768

Please sign in to comment.