Skip to content

Commit

Permalink
dump
Browse files Browse the repository at this point in the history
  • Loading branch information
gostkin committed Dec 27, 2023
1 parent 790e109 commit 36229c0
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 0 deletions.
80 changes: 80 additions & 0 deletions webserver/server/app/controllers/MintRangeController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Body, Controller, TsoaResponse, Res, Post, Route, SuccessResponse } from 'tsoa';
import { StatusCodes } from 'http-status-codes';
import tx from 'pg-tx';
import pool from '../services/PgPoolSingleton';

import { genErrorMessage } from '../../../shared/errors';
import { Errors } from '../../../shared/errors';
import type { ErrorShape } from '../../../shared/errors';
import type { EndpointTypes } from '../../../shared/routes';
import { Routes } from '../../../shared/routes';
import { MINT_RANGE_LIMIT } from "../../../shared/constants";
import { mintRange } from '../services/MintRangeService';
import type {MintRangeResponse} from "../../../shared/models/MintRange";

const route = Routes.mintRange;

@Route('assets/mint-range')
export class MintRangeController extends Controller {
@SuccessResponse(`${StatusCodes.OK}`)
@Post()
public async projectedNftRange(
@Body()
requestBody: EndpointTypes[typeof route]['input'],
@Res()
errorResponse: TsoaResponse<
StatusCodes.BAD_REQUEST | StatusCodes.CONFLICT | StatusCodes.UNPROCESSABLE_ENTITY,
ErrorShape
>
): Promise<EndpointTypes[typeof route]['response']> {
const slotRangeSize = requestBody.range.maxSlot - requestBody.range.minSlot;
if (slotRangeSize > MINT_RANGE_LIMIT.SLOT_RANGE) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return errorResponse(
StatusCodes.BAD_REQUEST,
genErrorMessage(Errors.SlotRangeLimitExceeded, {
limit: MINT_RANGE_LIMIT.SLOT_RANGE,
found: slotRangeSize,
})
);
}

if (requestBody.policyIds !== undefined && requestBody.policyIds.length > 0) {


return await this.handle_by_address_query(requestBody.address, requestBody);
} else {
return await this.handle_general_query(requestBody);
}
}

async handle_general_query(
requestBody: EndpointTypes[typeof route]['input'],
): Promise<EndpointTypes[typeof route]['response']> {
const response = await tx<
MintRangeResponse
>(pool, async dbTx => {
const data = await mintRange({
range: requestBody.range,
dbTx
});
return data.map(data => ({
ownerAddress: data.owner_address,
previousTxHash: data.previous_tx_hash,
previousTxOutputIndex: data.previous_tx_output_index != null ? parseInt(data.previous_tx_output_index) : null,
actionTxId: data.action_tx_id,
actionOutputIndex: data.action_output_index,
policyId: data.policy_id,
assetName: data.asset_name,
amount: data.amount,
status: data.status,
plutusDatum: data.plutus_datum,
actionSlot: data.action_slot,
forHowLong: data.for_how_long,
}));
});

return response;
}

}
46 changes: 46 additions & 0 deletions webserver/server/app/models/assets/sqlMintRange.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
@name sqlMintRange
*/
SELECT
"AssetMint".amount as amount,
encode("NativeAsset".policy_id, 'hex') as policy_id,
encode("NativeAsset".asset_name, 'hex') as asset_name,
"Cip25Entry".payload as cip25_data,
encode("Transaction".hash, 'hex') as action_tx_id,
"Block".slot as action_slot
FROM "AssetMint"
JOIN "NativeAsset" ON "NativeAsset".id = "AssetMint".asset_id
LEFT JOIN "TransactionMetadata" ON "TransactionMetadata".tx_id = "NativeAsset".first_tx
LEFT JOIN "Cip25Entry" ON
"Cip25Entry".asset_id = "NativeAsset".id
AND "Cip25Entry".metadata_id = "TransactionMetadata".id;
JOIN "Transaction" ON "Transaction".id = "AssetMint".tx_id
JOIN "Block" ON "Transaction".block_id = "Block".id
WHERE
"Block".slot > :min_slot!
AND "Block".slot <= :max_slot!
ORDER BY ("Block".height, "Transaction".tx_index) ASC;

/*
@name sqlMintRangeByPolicyIds
*/
SELECT
"AssetMint".amount as amount,
encode("NativeAsset".policy_id, 'hex') as policy_id,
encode("NativeAsset".asset_name, 'hex') as asset_name,
"Cip25Entry".payload as cip25_data,
encode("Transaction".hash, 'hex') as action_tx_id,
"Block".slot as action_slot
FROM "AssetMint"
JOIN "NativeAsset" ON "NativeAsset".id = "AssetMint".asset_id
LEFT JOIN "TransactionMetadata" ON "TransactionMetadata".tx_id = "NativeAsset".first_tx
LEFT JOIN "Cip25Entry" ON
"Cip25Entry".asset_id = "NativeAsset".id
AND "Cip25Entry".metadata_id = "TransactionMetadata".id;
JOIN "Transaction" ON "Transaction".id = "AssetMint".tx_id
JOIN "Block" ON "Transaction".block_id = "Block".id
WHERE
"Block".slot > :min_slot!
AND "Block".slot <= :max_slot!
AND "NativeAsset".policy_id IN :policy_ids!
ORDER BY ("Block".height, "Transaction".tx_index) ASC;
26 changes: 26 additions & 0 deletions webserver/server/app/services/MintRangeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { PoolClient } from 'pg';
import type { ISqlMintRangeResult} from '../models/assets/mintRange.queries';
import { sqlMintRange } from '../models/assets/mintRange.queries';
import type { PolicyId } from "../../../shared/models/PolicyIdAssetMap";

export async function mintRange(request: {
range: { minSlot: number, maxSlot: number },
dbTx: PoolClient,
}): Promise<ISqlMintRangeResult[]> {
return (await sqlMintRange.run({
min_slot: request.range.minSlot,
max_slot: request.range.maxSlot,
}, request.dbTx));
}

export async function mintRangeByPolicyIds(request: {
range: { minSlot: number, maxSlot: number },
policyIds: PolicyId[],
dbTx: PoolClient,
}): Promise<ISqlMintRangeResult[]> {
return (await sqlMintRangeByPolicyIds.run({
min_slot: request.range.minSlot,
max_slot: request.range.maxSlot,
policyIds: request.policyIds
}, request.dbTx));
}
54 changes: 54 additions & 0 deletions webserver/shared/models/MintRange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {AssetName, PolicyId} from "./PolicyIdAssetMap"

export type MintRangeRequest = {
/**
* Mint / Burn events in this slot range will be returned
*/
range: {
/**
* Minimal slot from which the events should be returned (not inclusive)
*
* @example 46154769
*/
minSlot: number,
/**
* Maximal slot from which the events should be returned (inclusive)
*
* @example 46154860
*/
maxSlot: number
},
policyIds: PolicyId[] | undefined
};

/**
* @example { "cip25": "a365636f6c6f72672330303030383065696d616765783a697066733a2f2f697066732f516d534b593167317a5375506b3536635869324b38524e766961526b44485633505a756a7474663755676b343379646e616d656a4265727279204e617679", "amount": "1" }
*/
export type Cip25MetadataAndAmount = {
cip25: string,
amount: string,
}

export type MintRangeResponse = {
/**
* Slot at which the transaction happened
*
* @example 512345
*/
actionSlot: number,

/**
* Assets changed in a particular transaction
*
* @example { "b863bc7369f46136ac1048adb2fa7dae3af944c3bbb2be2f216a8d4f": { "42657272794e617679": { "cip25": "a365636f6c6f72672330303030383065696d616765783a697066733a2f2f697066732f516d534b593167317a5375506b3536635869324b38524e766961526b44485633505a756a7474663755676b343379646e616d656a4265727279204e617679", "amount": "1" }}}
*/
cip25: { [policyId: string]: { [assetName: string]: Cip25MetadataAndAmount } };

/**
* Transaction id of related mint / burn event
*
* @pattern [0-9a-fA-F]{64}
* @example "28eb069e3e8c13831d431e3b2e35f58525493ab2d77fde83184993e4aa7a0eda"
*/
actionTxId: string,
}[];
10 changes: 10 additions & 0 deletions webserver/shared/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import type {
ProjectedNftRangeResponse,
} from "./models/ProjectedNftRange";
import { AssetUtxosRequest, AssetUtxosResponse } from "./models/AssetUtxos";
import type {
MintRangeRequest,
MintRangeResponse,
} from "./models/MintRange";

export enum Routes {
transactionHistory = "transaction/history",
Expand All @@ -47,6 +51,7 @@ export enum Routes {
delegationForPool = "delegation/pool",
projectedNftEventsRange = "projected-nft/range",
assetUtxos = "asset/utxos",
mintRange = "assets/mint-range",
}

export type EndpointTypes = {
Expand Down Expand Up @@ -115,4 +120,9 @@ export type EndpointTypes = {
input: AssetUtxosRequest;
response: AssetUtxosResponse;
};
[Routes.mintRange]: {
name: typeof Routes.mintRange;
input: MintRangeRequest;
response: MintRangeResponse;
};
};

0 comments on commit 36229c0

Please sign in to comment.