Skip to content

Commit

Permalink
asset utxos: add policy id filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
ecioppettini committed Dec 28, 2023
1 parent 97c8d4a commit d8b10f1
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 11 deletions.
11 changes: 8 additions & 3 deletions webserver/server/app/controllers/AssetUtxosController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,29 @@ export class AssetUtxosController extends Controller {
ErrorShape
>
): Promise<EndpointTypes[typeof route]['response']> {
if (requestBody.assets.length > ASSET_UTXOS_LIMIT.ASSETS) {
const assetsLength =
(requestBody.fingerprints?.length || 0) + (requestBody.policyIds?.length || 0);
if (assetsLength > ASSET_UTXOS_LIMIT.ASSETS) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return errorResponse(
StatusCodes.BAD_REQUEST,
genErrorMessage(Errors.AssetLimitExceeded, {
limit: ASSET_UTXOS_LIMIT.ASSETS,
found: requestBody.assets.length,
found: assetsLength,
})
);
}

const response = await tx<AssetUtxosResponse>(pool, async dbTx => {
const data = await getAssetUtxos({
range: requestBody.range,
assets: requestBody.assets.map(asset => {
fingerprints: requestBody.fingerprints?.map(asset => {
const decoded = bech32.decode(asset);
const payload = bech32.fromWords(decoded.words);

return Buffer.from(payload);
}),
policyIds: requestBody.policyIds?.map(policyId => Buffer.from(policyId, 'hex')),
dbTx,
});

Expand All @@ -69,6 +72,8 @@ export class AssetUtxosController extends Controller {
amount: data.amount ? data.amount : undefined,
slot: data.slot,
cip14Fingerprint: bech32.encode('asset', bech32.toWords(data.cip14_fingerprint)),
policyId: Buffer.from(data.policy_id).toString('hex'),
assetName: Buffer.from(data.asset_name).toString('hex'),
};
});
});
Expand Down
15 changes: 11 additions & 4 deletions webserver/server/app/models/asset/assetUtxos.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ import { PreparedQuery } from '@pgtyped/query';

/** 'AssetUtxos' parameters type */
export interface IAssetUtxosParams {
fingerprints: readonly (Buffer)[];
fingerprints: readonly (Buffer | null | void)[];
max_slot: number;
min_slot: number;
policyIds: readonly (Buffer | null | void)[];
}

/** 'AssetUtxos' return type */
export interface IAssetUtxosResult {
address_raw: Buffer;
amount: string | null;
asset_name: Buffer;
cip14_fingerprint: Buffer;
output_index: number;
output_tx_hash: string | null;
policy_id: Buffer;
slot: number;
tx_hash: string | null;
}
Expand All @@ -25,7 +28,7 @@ export interface IAssetUtxosQuery {
result: IAssetUtxosResult;
}

const assetUtxosIR: any = {"usedParamSet":{"fingerprints":true,"min_slot":true,"max_slot":true},"params":[{"name":"fingerprints","required":true,"transform":{"type":"array_spread"},"locs":[{"a":677,"b":690}]},{"name":"min_slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":712,"b":721}]},{"name":"max_slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":744,"b":753}]}],"statement":"SELECT ENCODE(TXO.HASH,\n 'hex') OUTPUT_TX_HASH,\n \"TransactionOutput\".OUTPUT_INDEX,\n\t\"NativeAsset\".CIP14_FINGERPRINT,\n\t\"AssetUtxo\".AMOUNT,\n\t\"Block\".SLOT,\n\tENCODE(\"Transaction\".HASH,\n 'hex') TX_HASH,\n\t\"Address\".PAYLOAD ADDRESS_RAW\nFROM \"AssetUtxo\"\nJOIN \"Transaction\" ON \"AssetUtxo\".TX_ID = \"Transaction\".ID\nJOIN \"TransactionOutput\" ON \"AssetUtxo\".UTXO_ID = \"TransactionOutput\".ID\nJOIN \"Transaction\" TXO ON \"TransactionOutput\".TX_ID = TXO.ID\nJOIN \"Address\" ON \"Address\".id = \"TransactionOutput\".address_id\nJOIN \"NativeAsset\" ON \"AssetUtxo\".ASSET_ID = \"NativeAsset\".ID\nJOIN \"Block\" ON \"Transaction\".BLOCK_ID = \"Block\".ID\nWHERE \n\t\"NativeAsset\".CIP14_FINGERPRINT IN :fingerprints! AND\n\t\"Block\".SLOT > :min_slot! AND\n\t\"Block\".SLOT <= :max_slot!\nORDER BY \"Transaction\".ID ASC"};
const assetUtxosIR: any = {"usedParamSet":{"fingerprints":true,"policyIds":true,"min_slot":true,"max_slot":true},"params":[{"name":"fingerprints","required":false,"transform":{"type":"array_spread"},"locs":[{"a":731,"b":743}]},{"name":"policyIds","required":false,"transform":{"type":"array_spread"},"locs":[{"a":777,"b":786}]},{"name":"min_slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":811,"b":820}]},{"name":"max_slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":843,"b":852}]}],"statement":"SELECT ENCODE(TXO.HASH,\n 'hex') OUTPUT_TX_HASH,\n \"TransactionOutput\".OUTPUT_INDEX,\n\t\"NativeAsset\".CIP14_FINGERPRINT,\n\t\"NativeAsset\".POLICY_ID,\n\t\"NativeAsset\".ASSET_NAME,\n\t\"AssetUtxo\".AMOUNT,\n\t\"Block\".SLOT,\n\tENCODE(\"Transaction\".HASH,\n 'hex') TX_HASH,\n\t\"Address\".PAYLOAD ADDRESS_RAW\nFROM \"AssetUtxo\"\nJOIN \"Transaction\" ON \"AssetUtxo\".TX_ID = \"Transaction\".ID\nJOIN \"TransactionOutput\" ON \"AssetUtxo\".UTXO_ID = \"TransactionOutput\".ID\nJOIN \"Transaction\" TXO ON \"TransactionOutput\".TX_ID = TXO.ID\nJOIN \"Address\" ON \"Address\".id = \"TransactionOutput\".address_id\nJOIN \"NativeAsset\" ON \"AssetUtxo\".ASSET_ID = \"NativeAsset\".ID\nJOIN \"Block\" ON \"Transaction\".BLOCK_ID = \"Block\".ID\nWHERE \n\t(\"NativeAsset\".CIP14_FINGERPRINT IN :fingerprints\n\t\tOR \"NativeAsset\".POLICY_ID IN :policyIds\n\t) AND\n\t\"Block\".SLOT > :min_slot! AND\n\t\"Block\".SLOT <= :max_slot!\nORDER BY \"Transaction\".ID, \"AssetUtxo\".ID ASC"};

/**
* Query generated from SQL:
Expand All @@ -34,6 +37,8 @@ const assetUtxosIR: any = {"usedParamSet":{"fingerprints":true,"min_slot":true,"
* 'hex') OUTPUT_TX_HASH,
* "TransactionOutput".OUTPUT_INDEX,
* "NativeAsset".CIP14_FINGERPRINT,
* "NativeAsset".POLICY_ID,
* "NativeAsset".ASSET_NAME,
* "AssetUtxo".AMOUNT,
* "Block".SLOT,
* ENCODE("Transaction".HASH,
Expand All @@ -47,10 +52,12 @@ const assetUtxosIR: any = {"usedParamSet":{"fingerprints":true,"min_slot":true,"
* JOIN "NativeAsset" ON "AssetUtxo".ASSET_ID = "NativeAsset".ID
* JOIN "Block" ON "Transaction".BLOCK_ID = "Block".ID
* WHERE
* "NativeAsset".CIP14_FINGERPRINT IN :fingerprints! AND
* ("NativeAsset".CIP14_FINGERPRINT IN :fingerprints
* OR "NativeAsset".POLICY_ID IN :policyIds
* ) AND
* "Block".SLOT > :min_slot! AND
* "Block".SLOT <= :max_slot!
* ORDER BY "Transaction".ID ASC
* ORDER BY "Transaction".ID, "AssetUtxo".ID ASC
* ```
*/
export const assetUtxos = new PreparedQuery<IAssetUtxosParams,IAssetUtxosResult>(assetUtxosIR);
Expand Down
7 changes: 6 additions & 1 deletion webserver/server/app/models/asset/assetUtxos.sql
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/*
@name AssetUtxos
@param fingerprints -> (...)
@param policyIds -> (...)
*/
SELECT ENCODE(TXO.HASH,
'hex') OUTPUT_TX_HASH,
"TransactionOutput".OUTPUT_INDEX,
"NativeAsset".CIP14_FINGERPRINT,
"NativeAsset".POLICY_ID,
"NativeAsset".ASSET_NAME,
"AssetUtxo".AMOUNT,
"Block".SLOT,
ENCODE("Transaction".HASH,
Expand All @@ -19,7 +22,9 @@ JOIN "Address" ON "Address".id = "TransactionOutput".address_id
JOIN "NativeAsset" ON "AssetUtxo".ASSET_ID = "NativeAsset".ID
JOIN "Block" ON "Transaction".BLOCK_ID = "Block".ID
WHERE
"NativeAsset".CIP14_FINGERPRINT IN :fingerprints! AND
("NativeAsset".CIP14_FINGERPRINT IN :fingerprints
OR "NativeAsset".POLICY_ID IN :policyIds
) AND
"Block".SLOT > :min_slot! AND
"Block".SLOT <= :max_slot!
ORDER BY "Transaction".ID, "AssetUtxo".ID ASC;
11 changes: 9 additions & 2 deletions webserver/server/app/services/AssetUtxos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,21 @@ export async function getAssetUtxos(request: {
minSlot: number;
maxSlot: number;
};
assets: Buffer[];
fingerprints?: Buffer[];
policyIds?: Buffer[];
dbTx: PoolClient;
}): Promise<IAssetUtxosResult[]> {
return await assetUtxos.run(
{
max_slot: request.range.maxSlot,
min_slot: request.range.minSlot,
fingerprints: request.assets,
// pgtyped doesn't seem to have a way to have an optional array parameter,
// and an empty spread expansion fails with postgres. Since none of these
// fields is nullable, an array with null should be equivalent to an empty
// array.
fingerprints:
request.fingerprints && request.fingerprints.length > 0 ? request.fingerprints : [null],
policyIds: request.policyIds && request.policyIds.length > 0 ? request.policyIds : [null],
},
request.dbTx
);
Expand Down
5 changes: 4 additions & 1 deletion webserver/shared/models/AssetUtxos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export type Cip14Fingerprint = string;

export type AssetUtxosRequest = {
range: { minSlot: number; maxSlot: number },
assets: Cip14Fingerprint[]
fingerprints?: Cip14Fingerprint[],
policyIds?: string[]
};

export type AssetUtxosResponse = {
Expand All @@ -22,6 +23,8 @@ export type AssetUtxosResponse = {
index: number,
},
cip14Fingerprint: string,
policyId: string,
assetName: string,
paymentCred: string,
slot: number
txId: string,
Expand Down

0 comments on commit d8b10f1

Please sign in to comment.