Skip to content

Commit

Permalink
Projected NFT funnel (#259)
Browse files Browse the repository at this point in the history
* add carp funnel with stake delegation pool tracking

* use local (tmp) carp client lib in the funnel

just to test until the up to date version is published on npm

* replace carp local client with 2.3.0 from npm

* handle presync in carp funnel

* use local (tmp) carp client lib in the funnel

just to test until the up to date version is published on npm

* add stopSlot setting to stop fetching

* address review comments

* Initial setups

* Queries & rebase

* Funnel fixes

* Lint & minor fixes

* More lint fixes

* Remove checks for owner address

* Address review comments

* Minor fixes

* number -> bigint for asset amount

* bigint -> string

* Update carp client and fix issue with big numbers in projected NFT

* Fix lint

* Asset -> policy id + asset name

* Update carp client call

* Fix paima tables

* Remove tsoa routes

* Address review comments

---------

Co-authored-by: Enzo Cioppettini <[email protected]>
  • Loading branch information
gostkin and ecioppettini authored Dec 29, 2023
1 parent 7ca0a23 commit 13f2781
Show file tree
Hide file tree
Showing 26 changed files with 2,362 additions and 1,095 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ bin

# logs
*.log

.idea/
2,520 changes: 1,455 additions & 1,065 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/batcher/address-validator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"pg": "^8.7.3",
"web3": "1.10.0",
"assert-never": "^1.2.1",
"@dcspark/carp-client": "^2.3.0"
"@dcspark/carp-client": "^2.3.1"
},
"devDependencies": {
"@types/pg": "^8.6.5"
Expand Down
Empty file modified packages/build-utils/paima-build-utils/scripts/change-db.js
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion packages/engine/paima-funnel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
},
"dependencies": {
"assert-never": "^1.2.1",
"@dcspark/carp-client": "^2.3.0"
"@dcspark/carp-client": "^2.3.1"
}
}
69 changes: 69 additions & 0 deletions packages/engine/paima-funnel/src/cde/cardanoProjectedNFT.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type {
CdeCardanoProjectedNFTDatum,
ChainDataExtensionCardanoProjectedNFT,
ChainDataExtensionDatum,
} from '@paima/sm';
import { ChainDataExtensionDatumType, DEFAULT_FUNNEL_TIMEOUT, timeout } from '@paima/utils';
import { Routes, query } from '@dcspark/carp-client/client/src';
import type { ProjectedNftRangeResponse } from '@dcspark/carp-client/shared/models/ProjectedNftRange';

export default async function getCdeProjectedNFTData(
url: string,
extension: ChainDataExtensionCardanoProjectedNFT,
fromAbsoluteSlot: number,
toAbsoluteSlot: number,
getBlockNumber: (slot: number) => number
): Promise<ChainDataExtensionDatum[]> {
const events = await timeout(
query(url, Routes.projectedNftEventsRange, {
range: { minSlot: fromAbsoluteSlot, maxSlot: toAbsoluteSlot },
address: undefined,
}),
DEFAULT_FUNNEL_TIMEOUT
);

return events
.map(e => eventToCdeDatum(e, extension, getBlockNumber(e.actionSlot)))
.filter(e => e != null)
.map(e => e!);
}

function eventToCdeDatum(
event: ProjectedNftRangeResponse[0],
extension: ChainDataExtensionCardanoProjectedNFT,
blockNumber: number
): CdeCardanoProjectedNFTDatum | null {
if (
event.actionTxId === null ||
event.actionTxId == '' ||
event.status === null ||
event.status == ''
) {
return null;
}

return {
cdeId: extension.cdeId,
cdeDatumType: ChainDataExtensionDatumType.CardanoProjectedNFT,
blockNumber,
payload: {
ownerAddress: event.ownerAddress != null ? event.ownerAddress : '',

actionTxId: event.actionTxId,
actionOutputIndex: event.actionOutputIndex != null ? event.actionOutputIndex : undefined,

previousTxHash: event.previousTxHash != null ? event.previousTxHash : undefined,
previousTxOutputIndex:
event.previousTxOutputIndex != null ? event.previousTxOutputIndex : undefined,

policyId: event.policyId,
assetName: event.assetName,
amount: event.amount,
status: event.status,
plutusDatum: event.plutusDatum != null ? event.plutusDatum : '',

forHowLong: event.forHowLong != null ? event.forHowLong : undefined,
},
scheduledPrefix: extension.scheduledPrefix,
};
}
4 changes: 4 additions & 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,10 @@ async function getSpecificCdeData(
// this is used by the block funnel, which can't get information for this
// extension
return [];
case ChainDataExtensionType.CardanoProjectedNFT:
// this is used by the block funnel, which can't get information for this
// extension
return [];
default:
assertNever(extension);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/paima-funnel/src/funnels/BaseFunnel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ChainData, ChainDataExtension, PresyncChainData } from '@paima/sm'
import type { PaimaL2Contract, Web3 } from '@paima/utils';
import type { FunnelCacheManager } from './FunnelCache.js';
import type { PoolClient } from 'pg';
import { FUNNEL_PRESYNC_FINISHED } from '@paima/utils';
import type { FUNNEL_PRESYNC_FINISHED } from '@paima/utils';

export type FunnelSharedData = {
readonly web3: Web3;
Expand Down
68 changes: 49 additions & 19 deletions packages/engine/paima-funnel/src/funnels/carp/funnel.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import {
ChainDataExtensionType,
DEFAULT_FUNNEL_TIMEOUT,
ENV,
Network,
delay,
doLog,
ENV,
logError,
Network,
timeout,
} from '@paima/utils';
import type { ChainDataExtensionDatum } from '@paima/sm';
import type { ChainDataExtensionCardanoProjectedNFT } from '@paima/sm';
import {
type ChainData,
type ChainDataExtension,
type ChainDataExtensionCardanoDelegation,
type ChainDataExtensionDatum,
type PresyncChainData,
} from '@paima/sm';
import { composeChainData, groupCdeData } from '../../utils.js';
import { BaseFunnel } from '../BaseFunnel.js';
import type { FunnelSharedData } from '../BaseFunnel.js';
import { BaseFunnel } from '../BaseFunnel.js';
import type { PoolClient } from 'pg';
import type { ChainFunnel, ReadPresyncDataFrom } from '@paima/runtime';
import getCdePoolData from '../../cde/cardanoPool.js';
import getCdeProjectedNFTData from '../../cde/cardanoProjectedNFT.js';
import { query } from '@dcspark/carp-client/client/src/index';
import { Routes } from '@dcspark/carp-client/shared/routes';
import { FUNNEL_PRESYNC_FINISHED } from '@paima/utils/src/constants';
Expand Down Expand Up @@ -140,27 +142,45 @@ export class CarpFunnel extends BaseFunnel implements ChainFunnel {
let basePromise = this.baseFunnel.readPresyncData(args);

if (arg && arg.from >= 0 && arg.from < this.cache.getState().startingSlot) {
const [poolEvents, data] = await Promise.all([
const [carpEvents, data] = await Promise.all([
Promise.all(
this.sharedData.extensions
.filter(extension => extension.cdeType === ChainDataExtensionType.CardanoPool)
.filter(
extension =>
extension.cdeType === ChainDataExtensionType.CardanoPool ||
extension.cdeType === ChainDataExtensionType.CardanoProjectedNFT
)
.map(extension => {
const data = getCdePoolData(
this.carpUrl,
extension as ChainDataExtensionCardanoDelegation,
arg.from,
Math.min(arg.to, this.cache.getState().startingSlot - 1),
slot => {
return slot;
}
);
return data;
if (extension.cdeType === ChainDataExtensionType.CardanoPool) {
const data = getCdePoolData(
this.carpUrl,
extension,
arg.from,
Math.min(arg.to, this.cache.getState().startingSlot - 1),
slot => {
return slot;
}
);
return data;
} else {
// ProjectedNFT
const data = getCdeProjectedNFTData(
this.carpUrl,
extension as ChainDataExtensionCardanoProjectedNFT,
arg.from,
Math.min(arg.to, this.cache.getState().startingSlot - 1),
slot => {
return slot;
}
);
return data;
}
})
),
basePromise,
]);

let grouped = groupCdeData(Network.CARDANO, arg.from, arg.to, poolEvents);
let grouped = groupCdeData(Network.CARDANO, arg.from, arg.to, carpEvents);

if (grouped.length > 0) {
data[Network.CARDANO] = grouped;
Expand Down Expand Up @@ -283,15 +303,25 @@ async function readDataInternal(

switch (extension.cdeType) {
case ChainDataExtensionType.CardanoPool:
const data = getCdePoolData(
const poolData = getCdePoolData(
carpUrl,
extension,
min,
Math.min(max, extension.stopSlot || max),
mapSlotToBlockNumber
);

return poolData;
case ChainDataExtensionType.CardanoProjectedNFT:
const projectedNFTData = getCdeProjectedNFTData(
carpUrl,
extension,
min,
Math.min(max, extension.stopSlot || max),
mapSlotToBlockNumber
);

return data;
return projectedNFTData;
default:
return Promise.resolve([]);
}
Expand Down
Loading

0 comments on commit 13f2781

Please sign in to comment.