Skip to content

Commit d142132

Browse files
authored
feat(api): include tokens in approval transactions (#1239)
* rename `token_transfers` to `token_actions` * ingest token approvals * update api * update tests * style: resolve style guide violations * simplify whitelist, remove POST for query param * update tests
1 parent c4b0fc2 commit d142132

32 files changed

Lines changed: 560 additions & 281 deletions

packages/api-database/source/contracts.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import type {
1212
State,
1313
System,
1414
Token,
15+
TokenAction,
1516
TokenHolder,
16-
TokenTransfer,
1717
TokenWhitelist,
1818
Transaction,
1919
ValidatorRound,
@@ -106,8 +106,8 @@ export type TokenRepositoryExtension = Record<string, unknown>;
106106
export type TokenRepository = ExtendedRepository<Token> & TokenRepositoryExtension;
107107
export type TokenHolderRepositoryExtension = Record<string, unknown>;
108108
export type TokenHolderRepository = ExtendedRepository<TokenHolder> & TokenHolderRepositoryExtension;
109-
export type TokenTransferRepositoryExtension = Record<string, unknown>;
110-
export type TokenTransferRepository = ExtendedRepository<TokenTransfer> & TokenTransferRepositoryExtension;
109+
export type TokenActionRepositoryExtension = Record<string, unknown>;
110+
export type TokenActionRepository = ExtendedRepository<TokenAction> & TokenActionRepositoryExtension;
111111
export type TokenWhitelistRepositoryExtension = Record<string, unknown>;
112112
export type TokenWhitelistRepository = ExtendedRepository<TokenWhitelist> & TokenWhitelistRepositoryExtension;
113113

@@ -142,7 +142,7 @@ export type PeerRepositoryFactory = (customDataSource?: RepositoryDataSource) =>
142142
export type TransactionRepositoryFactory = (customDataSource?: RepositoryDataSource) => TransactionRepository;
143143
export type TokenRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenRepository;
144144
export type TokenHolderRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenHolderRepository;
145-
export type TokenTransferRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenTransferRepository;
145+
export type TokenActionRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenActionRepository;
146146
export type TokenWhitelistRepositoryFactory = (customDataSource?: RepositoryDataSource) => TokenWhitelistRepository;
147147
export type MultiPaymentRepositoryFactory = (customDataSource?: RepositoryDataSource) => MultiPaymentRepository;
148148
export type ValidatorRoundRepositoryFactory = (customDataSource?: RepositoryDataSource) => ValidatorRoundRepository;

packages/api-database/source/identifiers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ export const Identifiers = {
1111
PluginRepositoryFactory: Symbol.for("API<Factory.PluginRepositoryFactory>"),
1212
StateRepositoryFactory: Symbol.for("API<Factory.StateRepositoryFactory>"),
1313
SystemRepositoryFactory: Symbol.for("API<Factory.SystemRepositoryFactory>"),
14+
TokenActionRepositoryFactory: Symbol.for("API<Factory.TokenActionRepositoryFactory>"),
1415
TokenHolderRepositoryFactory: Symbol.for("API<Factory.TokenHolderRepositoryFactory>"),
1516
TokenRepositoryFactory: Symbol.for("API<Factory.TokenRepositoryFactory>"),
16-
TokenTransferRepositoryFactory: Symbol.for("API<Factory.TokenTransferRepositoryFactory>"),
1717
TokenWhitelistRepositoryFactory: Symbol.for("API<Factory.TokenWhitelistRepositoryFactory>"),
1818
TransactionRepositoryFactory: Symbol.for("API<Factory.TransactionRepositoryFactory>"),
1919
ValidatorRoundRepositoryFactory: Symbol.for("API<Factory.ValidatorRoundRepositoryFactory>"),

packages/api-database/source/migrations/1697617471901-CreateIndexes.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ export class CreateIndexes1697617471901 implements MigrationInterface {
5757
CREATE INDEX token_holders_address_token ON token_holders ("address", "token_address");
5858
CREATE INDEX token_holders_token_address_balance ON token_holders ("address", "token_address", "balance");
5959
60-
CREATE INDEX token_transfers_all ON token_transfers ("block_number" DESC, "index" DESC);
61-
CREATE INDEX token_transfers_all_from ON token_transfers ("from", "block_number" DESC, "index" DESC);
62-
CREATE INDEX token_transfers_all_to ON token_transfers ("to", "block_number" DESC, "index" DESC);
63-
CREATE INDEX token_transfers_address ON token_transfers ("address", "block_number" DESC, "index" DESC);
64-
CREATE INDEX token_transfers_address_from ON token_transfers ("address", "from", "block_number" DESC, "index" DESC);
65-
CREATE INDEX token_transfers_address_to ON token_transfers ("address", "to", "block_number" DESC, "index" DESC );
66-
CREATE INDEX token_transfers_tx_hash ON token_transfers ("transaction_hash");
60+
CREATE INDEX token_actions_all ON token_actions (action, "block_number" DESC, "index" DESC);
61+
CREATE INDEX token_actions_all_from ON token_actions (action, "from", "block_number" DESC, "index" DESC);
62+
CREATE INDEX token_actions_all_to ON token_actions (action, "to", "block_number" DESC, "index" DESC);
63+
CREATE INDEX token_actions_address ON token_actions (action, "address", "block_number" DESC, "index" DESC);
64+
CREATE INDEX token_actions_address_from ON token_actions (action, "address", "from", "block_number" DESC, "index" DESC);
65+
CREATE INDEX token_actions_address_to ON token_actions (action, "address", "to", "block_number" DESC, "index" DESC );
66+
CREATE INDEX token_actions_tx_hash ON token_actions ("transaction_hash");
6767
6868
-- when >= 3 chars
6969
CREATE INDEX tokens_symbol_trgm ON tokens USING gin (symbol gin_trgm_ops);
@@ -130,13 +130,13 @@ export class CreateIndexes1697617471901 implements MigrationInterface {
130130
DROP INDEX token_holders_address_token;
131131
DROP INDEX token_holders_token_address_balance;
132132
133-
DROP INDEX token_transfers_all;
134-
DROP INDEX token_transfers_all_from;
135-
DROP INDEX token_transfers_all_to;
136-
DROP INDEX token_transfers_address;
137-
DROP INDEX token_transfers_address_from;
138-
DROP INDEX token_transfers_address_to;
139-
DROP INDEX token_transfers_tx_hash;
133+
DROP INDEX token_actions_all;
134+
DROP INDEX token_actions_all_from;
135+
DROP INDEX token_actions_all_to;
136+
DROP INDEX token_actions_address;
137+
DROP INDEX token_actions_address_from;
138+
DROP INDEX token_actions_address_to;
139+
DROP INDEX token_actions_tx_hash;
140140
`);
141141
}
142142
}

packages/api-database/source/models/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export * from "./plugin.js";
99
export * from "./state.js";
1010
export * from "./system.js";
1111
export * from "./token.js";
12+
export * from "./token-action.js";
1213
export * from "./token-holder.js";
13-
export * from "./token-transfers.js";
1414
export * from "./token-whitelist.js";
1515
export * from "./transaction.js";
1616
export * from "./validator-round.js";

packages/api-database/source/models/token-transfers.ts renamed to packages/api-database/source/models/token-action.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
import { Column, Entity } from "typeorm";
22

3+
export enum TokenActionEnum {
4+
Transfer = "Transfer",
5+
Approval = "Approval",
6+
}
7+
38
@Entity({
4-
name: "token_transfers",
9+
name: "token_actions",
510
})
6-
export class TokenTransfer {
11+
export class TokenAction {
712
@Column({
813
primary: true,
914
type: "citext",
1015
})
1116
public readonly address!: string;
1217

18+
@Column({
19+
enum: TokenActionEnum,
20+
enumName: "token_action_enum",
21+
primary: true,
22+
type: "enum",
23+
})
24+
public readonly action!: string;
25+
1326
@Column({
1427
primary: true,
1528
type: "bigint",

packages/api-database/source/repositories/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export { makePeerRepository } from "./peer-repository.js";
77
export { makePluginRepository } from "./plugin-repository.js";
88
export { makeStateRepository } from "./state-repository.js";
99
export { makeSystemRepository } from "./system-repository.js";
10+
export { makeTokenActionRepository } from "./token-action-repository.js";
1011
export { makeTokenHolderRepository } from "./token-holder-repository.js";
1112
export { makeTokenRepository } from "./token-repository.js";
12-
export { makeTokenTransferRepository } from "./token-transfer-repository.js";
1313
export { makeTokenWhitelistRepository } from "./token-whitelist-repository.js";
1414
export { makeTransactionRepository } from "./transaction-repository.js";
1515
export { makeValidatorRoundRepository } from "./validator-round-repository.js";
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { RepositoryDataSource, TokenActionRepository, TokenActionRepositoryExtension } from "../contracts.js";
2+
import { TokenAction } from "../models/index.js";
3+
import { makeExtendedRepository } from "./repository-extension.js";
4+
5+
export const makeTokenActionRepository = (dataSource: RepositoryDataSource): TokenActionRepository =>
6+
makeExtendedRepository<TokenAction, TokenActionRepositoryExtension>(TokenAction, dataSource, {
7+
// Add any extensions here
8+
});

packages/api-database/source/repositories/token-transfer-repository.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/api-database/source/service-provider.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import {
1717
RepositoryDataSource,
1818
StateRepository,
1919
SystemRepository,
20+
TokenActionRepository,
2021
TokenHolderRepository,
2122
TokenRepository,
22-
TokenTransferRepository,
2323
TokenWhitelistRepository,
2424
TransactionRepository,
2525
ValidatorRoundRepository,
@@ -39,8 +39,8 @@ import {
3939
State,
4040
System,
4141
Token,
42+
TokenAction,
4243
TokenHolder,
43-
TokenTransfer,
4444
TokenWhitelist,
4545
Transaction,
4646
ValidatorRound,
@@ -57,9 +57,9 @@ import {
5757
makePluginRepository,
5858
makeStateRepository,
5959
makeSystemRepository,
60+
makeTokenActionRepository,
6061
makeTokenHolderRepository,
6162
makeTokenRepository,
62-
makeTokenTransferRepository,
6363
makeTokenWhitelistRepository,
6464
makeTransactionRepository,
6565
makeValidatorRoundRepository,
@@ -108,8 +108,8 @@ export class ServiceProvider extends Providers.ServiceProvider {
108108
System,
109109
Transaction,
110110
Token,
111+
TokenAction,
111112
TokenHolder,
112-
TokenTransfer,
113113
TokenWhitelist,
114114
MultiPayment,
115115
ValidatorRound,
@@ -218,10 +218,10 @@ export class ServiceProvider extends Providers.ServiceProvider {
218218
);
219219

220220
this.app
221-
.bind<() => TokenTransferRepository>(Identifiers.TokenTransferRepositoryFactory)
221+
.bind<() => TokenActionRepository>(Identifiers.TokenActionRepositoryFactory)
222222
.toFactory(
223223
() => (customDataSource?: RepositoryDataSource) =>
224-
makeTokenTransferRepository(customDataSource ?? dataSource),
224+
makeTokenActionRepository(customDataSource ?? dataSource),
225225
);
226226

227227
this.app

packages/api-http/integration/routes/tokens.test.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import tokens from "../../test/fixtures/tokens.json";
77
import tokenHolders from "../../test/fixtures/token_holders.json";
88
import tokenTransferTokens from "../../test/fixtures/token_transfer.tokens.json";
99
import tokenTransferTransactions from "../../test/fixtures/token_transfer.transactions.json";
10-
import tokenTransfers from "../../test/fixtures/token_transfers.json";
10+
import tokenActions from "../../test/fixtures/token_actions.json";
1111
import tokenWhitelist from "../../test/fixtures/token_whitelist.json";
1212
import tokenTransfersResponse from "../../test/fixtures/token_transfers.response.json";
13+
import tokenApprovalsResponse from "../../test/fixtures/token_approvals.response.json";
1314

1415
describe<{
1516
app: Application;
@@ -150,54 +151,48 @@ describe<{
150151
}
151152
});
152153

153-
it("/tokens custom whitelist (POST)", async () => {
154+
it("/tokens?whitelist", async () => {
154155
await apiContext.tokenRepository.save(tokens);
155156
await apiContext.tokenWhitelistRepository.save(tokenWhitelist.slice(0, 1));
156157

157158
const testCases = [
158159
{
159160
query: "",
160-
method: "POST",
161161
result: {
162162
data: [tokens[0]],
163163
statusCode: 200,
164164
},
165165
},
166166
{
167-
query: "",
168-
body: JSON.stringify({ whitelist: [tokens[1].address] }),
169-
method: "POST",
167+
query: `?whitelist=${tokens[1].address}`,
170168
result: {
171169
data: [tokens[0], tokens[1]],
172170
statusCode: 200,
173171
},
174172
},
175173
{
176-
query: "",
177-
body: JSON.stringify({ whitelist: tokens.map((t) => t.address) }),
178-
method: "POST",
174+
query: `?whitelist=${tokens.map((t) => t.address).join(",")}`,
179175
result: {
180176
data: [...tokens].sort((a, b) => a.address.localeCompare(b.address)),
181177
statusCode: 200,
182178
},
183179
},
184180
{
185-
query: "",
181+
query: `?whitelist=0x0000000000000000000000000000000000000000`,
186182
body: JSON.stringify({ whitelist: ["0x0000000000000000000000000000000000000000"] }),
187-
method: "POST",
188183
result: {
189184
data: [tokens[0]],
190185
statusCode: 200,
191186
},
192187
},
193188
];
194189

195-
for (const { query, result, body, method } of testCases) {
190+
for (const { query, result } of testCases) {
196191
const endpoint = `/tokens${query}`;
197192
if (result.statusCode === 404) {
198193
await assert.rejects(async () => request(endpoint, options), "Response code 404 (Not Found)");
199194
} else {
200-
const { statusCode, data } = await request(endpoint, { ...options, body, method });
195+
const { statusCode, data } = await request(endpoint, { ...options });
201196
assert.equal(statusCode, result.statusCode);
202197
assert.equal(data.data, result.data);
203198
}
@@ -289,7 +284,7 @@ describe<{
289284
it("/tokens/transfers", async () => {
290285
await apiContext.tokenRepository.save(tokenTransferTokens);
291286
await apiContext.transactionRepository.save(tokenTransferTransactions);
292-
await apiContext.tokenTransferRepository.save(tokenTransfers);
287+
await apiContext.tokenActionRepository.save(tokenActions);
293288
await apiContext.tokenWhitelistRepository.save(tokenWhitelist);
294289

295290
const testCases = [
@@ -380,7 +375,7 @@ describe<{
380375
it("/tokens/{}/transfers", async () => {
381376
await apiContext.tokenRepository.save(tokenTransferTokens);
382377
await apiContext.transactionRepository.save(tokenTransferTransactions);
383-
await apiContext.tokenTransferRepository.save(tokenTransfers);
378+
await apiContext.tokenActionRepository.save(tokenActions);
384379
await apiContext.tokenWhitelistRepository.save(tokenWhitelist);
385380

386381
const testCases = [
@@ -412,4 +407,40 @@ describe<{
412407
}
413408
}
414409
});
410+
411+
it("/tokens/{}/approvals", async () => {
412+
await apiContext.tokenRepository.save(tokenTransferTokens);
413+
await apiContext.transactionRepository.save(tokenTransferTransactions);
414+
await apiContext.tokenActionRepository.save(tokenActions);
415+
await apiContext.tokenWhitelistRepository.save(tokenWhitelist);
416+
417+
const testCases = [
418+
{
419+
query: "",
420+
token: tokenTransferTokens[1].address,
421+
result: {
422+
data: tokenApprovalsResponse.filter((t) => t.token.address === tokenTransferTokens[1].address),
423+
statusCode: 200,
424+
},
425+
},
426+
{
427+
query: "",
428+
token: "0xdead78251073157e400c3d8d2ed92a85c958f9fa",
429+
result: {
430+
statusCode: 404,
431+
},
432+
},
433+
];
434+
435+
for (const { query, token, result } of testCases) {
436+
const endpoint = `/tokens/${token}/approvals${query}`;
437+
if (result.statusCode === 404) {
438+
await assert.rejects(async () => request(endpoint, options), "Response code 404 (Not Found)");
439+
} else {
440+
const { statusCode, data } = await request(endpoint, options);
441+
assert.equal(statusCode, result.statusCode);
442+
assert.equal(data.results, result.data);
443+
}
444+
}
445+
});
415446
});

0 commit comments

Comments
 (0)