Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/api-database/source/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
Token,
TokenHolder,
TokenTransfer,
TokenWhitelist,
Transaction,
ValidatorRound,
Wallet,
Expand Down Expand Up @@ -107,6 +108,8 @@ export type TokenHolderRepositoryExtension = Record<string, unknown>;
export type TokenHolderRepository = ExtendedRepository<TokenHolder> & TokenHolderRepositoryExtension;
export type TokenTransferRepositoryExtension = Record<string, unknown>;
export type TokenTransferRepository = ExtendedRepository<TokenTransfer> & TokenTransferRepositoryExtension;
export type TokenWhitelistRepositoryExtension = Record<string, unknown>;
export type TokenWhitelistRepository = ExtendedRepository<TokenWhitelist> & TokenWhitelistRepositoryExtension;

export type SystemRepositoryExtension = {
inMaintenance(): Promise<boolean>;
Expand Down Expand Up @@ -140,6 +143,7 @@ export type TransactionRepositoryFactory = (customDataSource?: RepositoryDataSou
export type TokenRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenRepository;
export type TokenHolderRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenHolderRepository;
export type TokenTransferRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenTransferRepository;
export type TokenWhitelistRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenWhitelistRepository;
export type MultiPaymentRepositoryFactory = (customDataSource?: RepositoryDataSource) => MultiPaymentRepository;
export type ValidatorRoundRepositoryFactory = (customDataSource?: RepositoryDataSource) => ValidatorRoundRepository;
export type PluginRepositoryFactory = (customDataSource?: RepositoryDataSource) => PluginRepository;
Expand Down
1 change: 1 addition & 0 deletions packages/api-database/source/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const Identifiers = {
TokenHolderRepositoryFactory: Symbol.for("API<Factory.TokenHolderRepositoryFactory>"),
TokenRepositoryFactory: Symbol.for("API<Factory.TokenRepositoryFactory>"),
TokenTransferRepositoryFactory: Symbol.for("API<Factory.TokenTransferRepositoryFactory>"),
TokenWhitelistRepositoryFactory: Symbol.for("API<Factory.TokenWhitelistRepositoryFactory>"),
TransactionRepositoryFactory: Symbol.for("API<Factory.TransactionRepositoryFactory>"),
ValidatorRoundRepositoryFactory: Symbol.for("API<Factory.ValidatorRoundRepositoryFactory>"),
WalletRepositoryFactory: Symbol.for("API<Factory.WalletRepositoryFactory>"),
Expand Down
5 changes: 3 additions & 2 deletions packages/api-database/source/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ export * from "./plugin.js";
export * from "./state.js";
export * from "./system.js";
export * from "./token.js";
export * from "./token_holder.js";
export * from "./token_transfers.js";
export * from "./token-holder.js";
export * from "./token-transfers.js";
export * from "./token-whitelist.js";
export * from "./transaction.js";
export * from "./validator-round.js";
export * from "./wallet.js";
Expand Down
25 changes: 25 additions & 0 deletions packages/api-database/source/models/token-whitelist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Column, Entity } from "typeorm";

@Entity({
name: "token_whitelist",
})
export class TokenWhitelist {
@Column({
primary: true,
type: "citext",
})
public readonly address!: string;

@Column({
default: undefined,
nullable: true,
type: "text",
})
public readonly comment: string | undefined;

@Column({
nullable: false,
type: "timestamptz",
})
public readonly createdAt!: string;
}
26 changes: 13 additions & 13 deletions packages/api-database/source/models/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Column, Entity, VirtualColumn } from "typeorm";
import { Column, Entity } from "typeorm";

@Entity({
name: "wallets",
Expand Down Expand Up @@ -36,18 +36,18 @@ export class Wallet {
})
public attributes: string | undefined;

@VirtualColumn({
query: (alias) => `
COALESCE(
(SELECT tc.token_count
FROM wallet_token_counts tc
WHERE tc.address = ${alias}.address
LIMIT 1),
0
)`,
type: "integer",
})
public tokenCount: number | undefined;
// @VirtualColumn({
// query: (alias) => `
// COALESCE(
// (SELECT tc.token_count
// FROM wallet_token_counts tc
// WHERE tc.address = ${alias}.address
// LIMIT 1),
// 0
// )`,
// type: "integer",
// })
// public tokenCount: number | undefined;

@Column({
nullable: false,
Expand Down
1 change: 1 addition & 0 deletions packages/api-database/source/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { makeSystemRepository } from "./system-repository.js";
export { makeTokenHolderRepository } from "./token-holder-repository.js";
export { makeTokenRepository } from "./token-repository.js";
export { makeTokenTransferRepository } from "./token-transfer-repository.js";
export { makeTokenWhitelistRepository } from "./token-whitelist-repository.js";
export { makeTransactionRepository } from "./transaction-repository.js";
export { makeValidatorRoundRepository } from "./validator-round-repository.js";
export { makeWalletRepository } from "./wallet-repository.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {
RepositoryDataSource,
TokenWhitelistRepository,
TokenWhitelistRepositoryExtension,
} from "../contracts.js";
import { TokenWhitelist } from "../models/index.js";
import { makeExtendedRepository } from "./repository-extension.js";

export const makeTokenWhitelistRepository = (dataSource: RepositoryDataSource): TokenWhitelistRepository =>
makeExtendedRepository<TokenWhitelist, TokenWhitelistRepositoryExtension>(TokenWhitelist, dataSource, {
// Add any extensions here
});
11 changes: 11 additions & 0 deletions packages/api-database/source/service-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
TokenHolderRepository,
TokenRepository,
TokenTransferRepository,
TokenWhitelistRepository,
TransactionRepository,
ValidatorRoundRepository,
WalletRepository,
Expand All @@ -40,6 +41,7 @@ import {
Token,
TokenHolder,
TokenTransfer,
TokenWhitelist,
Transaction,
ValidatorRound,
Wallet,
Expand All @@ -58,6 +60,7 @@ import {
makeTokenHolderRepository,
makeTokenRepository,
makeTokenTransferRepository,
makeTokenWhitelistRepository,
makeTransactionRepository,
makeValidatorRoundRepository,
makeWalletRepository,
Expand Down Expand Up @@ -107,6 +110,7 @@ export class ServiceProvider extends Providers.ServiceProvider {
Token,
TokenHolder,
TokenTransfer,
TokenWhitelist,
MultiPayment,
ValidatorRound,
Wallet,
Expand Down Expand Up @@ -220,6 +224,13 @@ export class ServiceProvider extends Providers.ServiceProvider {
makeTokenTransferRepository(customDataSource ?? dataSource),
);

this.app
.bind<() => TokenWhitelistRepository>(Identifiers.TokenWhitelistRepositoryFactory)
.toFactory(
() => (customDataSource?: RepositoryDataSource) =>
makeTokenWhitelistRepository(customDataSource ?? dataSource),
);

this.app
.bind<() => ValidatorRoundRepository>(Identifiers.ValidatorRoundRepositoryFactory)
.toFactory(
Expand Down
95 changes: 95 additions & 0 deletions packages/api-http/integration/routes/tokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import tokenHolders from "../../test/fixtures/token_holders.json";
import tokenTransferTokens from "../../test/fixtures/token_transfer.tokens.json";
import tokenTransferTransactions from "../../test/fixtures/token_transfer.transactions.json";
import tokenTransfers from "../../test/fixtures/token_transfers.json";
import tokenWhitelist from "../../test/fixtures/token_whitelist.json";
import tokenTransfersResponse from "../../test/fixtures/token_transfers.response.json";

describe<{
Expand Down Expand Up @@ -37,6 +38,7 @@ describe<{

it("/tokens", async () => {
await apiContext.tokenRepository.save(tokens);
await apiContext.tokenWhitelistRepository.save(tokenWhitelist);

const testCases = [
{
Expand Down Expand Up @@ -109,6 +111,99 @@ describe<{
}
});

it("/tokens?ignoreWhitelist", async () => {
await apiContext.tokenRepository.save(tokens);

const testCases = [
{
query: "?ignoreWhitelist=true",
result: {
data: [...tokens].sort((a, b) => a.address.localeCompare(b.address)),
statusCode: 200,
},
},
{
query: "?ignoreWhitelist=false",
result: {
data: [],
statusCode: 200,
},
},
{
query: "",
result: {
data: [],
statusCode: 200,
},
},
];

for (const { query, result } of testCases) {
const endpoint = `/tokens${query}`;
if (result.statusCode === 404) {
await assert.rejects(async () => request(endpoint, options), "Response code 404 (Not Found)");
} else {
const { statusCode, data } = await request(endpoint, options);
assert.equal(statusCode, result.statusCode);
assert.equal(data.data, result.data);
}
}
});

it("/tokens custom whitelist (POST)", async () => {
await apiContext.tokenRepository.save(tokens);
await apiContext.tokenWhitelistRepository.save(tokenWhitelist.slice(0, 1));

const testCases = [
{
query: "",
method: "POST",
result: {
data: [tokens[0]],
statusCode: 200,
},
},
{
query: "",
body: JSON.stringify({ whitelist: [tokens[1].address] }),
method: "POST",
result: {
data: [tokens[0], tokens[1]],
statusCode: 200,
},
},
{
query: "",
body: JSON.stringify({ whitelist: tokens.map((t) => t.address) }),
method: "POST",
result: {
data: [...tokens].sort((a, b) => a.address.localeCompare(b.address)),
statusCode: 200,
},
},
{
query: "",
body: JSON.stringify({ whitelist: ["0x0000000000000000000000000000000000000000"] }),
method: "POST",
result: {
data: [tokens[0]],
statusCode: 200,
},
},
];

for (const { query, result, body, method } of testCases) {
const endpoint = `/tokens${query}`;
if (result.statusCode === 404) {
await assert.rejects(async () => request(endpoint, options), "Response code 404 (Not Found)");
} else {
const { statusCode, data } = await request(endpoint, { ...options, body, method });
assert.equal(statusCode, result.statusCode);
assert.equal(data.data, result.data);
}
}
});

it("/tokens/{}", async () => {
await apiContext.tokenRepository.save(tokens);

Expand Down
Loading
Loading