Skip to content

Commit

Permalink
add 'delegation/address' route
Browse files Browse the repository at this point in the history
  • Loading branch information
ecioppettini committed Oct 3, 2023
1 parent e276231 commit 9d1dda3
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 1 deletion.
59 changes: 59 additions & 0 deletions webserver/server/app/controllers/DelegationForAddressController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
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 type { ErrorShape } from '../../../shared/errors';
import { genErrorMessage } from '../../../shared/errors';
import { Errors } from '../../../shared/errors';
import type { EndpointTypes } from '../../../shared/routes';
import { Routes } from '../../../shared/routes';
import { getAddressTypes } from '../models/utils';
import { delegationForAddress } from '../services/Delegation';
import { DelegationForAddressResponse } from '../../../shared/models/DelegationForAddress';

const route = Routes.delegationForAddress;

@Route('delegation/address')
export class DelegationForAddressController extends Controller {
@SuccessResponse(`${StatusCodes.OK}`)
@Post()
public async delegationForAddress(
@Body()
requestBody: EndpointTypes[typeof route]['input'],
@Res()
errorResponse: TsoaResponse<
StatusCodes.BAD_REQUEST | StatusCodes.CONFLICT | StatusCodes.UNPROCESSABLE_ENTITY,
ErrorShape
>
): Promise<EndpointTypes[typeof route]['response']> {
const addressTypes = getAddressTypes([requestBody.address]);

if (addressTypes.invalid.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return errorResponse(
StatusCodes.UNPROCESSABLE_ENTITY,
genErrorMessage(Errors.IncorrectAddressFormat, {
addresses: addressTypes.invalid,
})
);
}

const response = await tx<
DelegationForAddressResponse
>(pool, async dbTx => {
const data = await delegationForAddress({
address: addressTypes.credentialHex.map(addr => Buffer.from(addr, 'hex'))[0],
until: requestBody.until,
dbTx
});

return {
pool: data ? data.pool : null,
txId: data ? data.tx_id : null,
}
});

return response;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/** Types generated for queries found in "app/models/delegation/delegationForAddress.sql" */
import { PreparedQuery } from '@pgtyped/query';

/** 'SqlStakeDelegation' parameters type */
export interface ISqlStakeDelegationParams {
credential: Buffer;
slot: number;
}

/** 'SqlStakeDelegation' return type */
export interface ISqlStakeDelegationResult {
pool: string | null;
tx_id: string | null;
}

/** 'SqlStakeDelegation' query type */
export interface ISqlStakeDelegationQuery {
params: ISqlStakeDelegationParams;
result: ISqlStakeDelegationResult;
}

const sqlStakeDelegationIR: any = {"usedParamSet":{"credential":true,"slot":true},"params":[{"name":"credential","required":true,"transform":{"type":"scalar"},"locs":[{"a":371,"b":382}]},{"name":"slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":405,"b":410}]}],"statement":"SELECT encode(pool_credential, 'hex') as pool, encode(\"Transaction\".hash, 'hex') as tx_id\nFROM \"StakeDelegationCredentialRelation\"\nJOIN \"StakeCredential\" ON stake_credential = \"StakeCredential\".id\nJOIN \"Transaction\" ON \"Transaction\".id = \"StakeDelegationCredentialRelation\".tx_id\nJOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\nWHERE \n\t\"StakeCredential\".credential = :credential! AND\n\t\"Block\".slot <= :slot!\nORDER BY (\"Block\".height, \"Transaction\".tx_index) DESC\nLIMIT 1"};

/**
* Query generated from SQL:
* ```
* SELECT encode(pool_credential, 'hex') as pool, encode("Transaction".hash, 'hex') as tx_id
* FROM "StakeDelegationCredentialRelation"
* JOIN "StakeCredential" ON stake_credential = "StakeCredential".id
* JOIN "Transaction" ON "Transaction".id = "StakeDelegationCredentialRelation".tx_id
* JOIN "Block" ON "Transaction".block_id = "Block".id
* WHERE
* "StakeCredential".credential = :credential! AND
* "Block".slot <= :slot!
* ORDER BY ("Block".height, "Transaction".tx_index) DESC
* LIMIT 1
* ```
*/
export const sqlStakeDelegation = new PreparedQuery<ISqlStakeDelegationParams,ISqlStakeDelegationResult>(sqlStakeDelegationIR);


11 changes: 11 additions & 0 deletions webserver/server/app/models/delegation/delegationForAddress.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* @name sqlStakeDelegation */
SELECT encode(pool_credential, 'hex') as pool, encode("Transaction".hash, 'hex') as tx_id
FROM "StakeDelegationCredentialRelation"
JOIN "StakeCredential" ON stake_credential = "StakeCredential".id
JOIN "Transaction" ON "Transaction".id = "StakeDelegationCredentialRelation".tx_id
JOIN "Block" ON "Transaction".block_id = "Block".id
WHERE
"StakeCredential".credential = :credential! AND
"Block".slot <= :slot!
ORDER BY ("Block".height, "Transaction".tx_index) DESC
LIMIT 1;
12 changes: 12 additions & 0 deletions webserver/server/app/services/Delegation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import type { PoolClient } from 'pg';
import { ISqlStakeDelegationResult, sqlStakeDelegation } from '../models/delegation/delegationForAddress.queries';


export async function delegationForAddress(request: {
address: Buffer,
until: { absoluteSlot: number },
dbTx: PoolClient,
}): Promise<ISqlStakeDelegationResult> {
return (await sqlStakeDelegation.run({ credential: request.address, slot: request.until.absoluteSlot }, request.dbTx))[0];
}
11 changes: 11 additions & 0 deletions webserver/shared/models/DelegationForAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Address } from "./Address";

export type DelegationForAddressRequest = {
address: Address;
until: { absoluteSlot: number }
};

export type DelegationForAddressResponse = {
pool: string | null;
txId: string | null;
};
12 changes: 11 additions & 1 deletion webserver/shared/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import type {
TransactionOutputRequest,
TransactionOutputResponse,
} from "./models/TransactionOutput";
import type {
DelegationForAddressRequest,
DelegationForAddressResponse,
} from "./models/DelegationForAddress";

export enum Routes {
transactionHistory = "transaction/history",
Expand All @@ -29,7 +33,8 @@ export enum Routes {
metadataNft = "metadata/nft",
dexMeanPrice = "dex/mean-price",
dexSwap = "dex/swap",
dexLastPrice = "dex/last-price"
dexLastPrice = "dex/last-price",
delegationForAddress = "delegation/address",
}

export type EndpointTypes = {
Expand Down Expand Up @@ -78,4 +83,9 @@ export type EndpointTypes = {
input: DexLastPriceRequest;
response: DexLastPriceResponse;
};
[Routes.delegationForAddress]: {
name: typeof Routes.delegationForAddress;
input: DelegationForAddressRequest;
response: DelegationForAddressResponse;
};
};

0 comments on commit 9d1dda3

Please sign in to comment.