Skip to content

Commit

Permalink
Improve multisig account fetching
Browse files Browse the repository at this point in the history
  • Loading branch information
serjonya-trili committed Sep 13, 2024
1 parent d0829fd commit c9f0144
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 55 deletions.
126 changes: 89 additions & 37 deletions packages/multisig/src/fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,14 @@ import {
getExistingContracts,
getPendingOperationsForMultisigs,
} from "./fetch";
import range from "lodash/range";

Check warning on line 12 in packages/multisig/src/fetch.test.ts

View workflow job for this annotation

GitHub Actions / test

`lodash/range` import should occur before import of `./fetch`

const mockedAxios = jest.spyOn(axios, "get");

const mockedContractsGet = jest.spyOn(api, "contractsGet");
const mockedContractsGetCount = jest.spyOn(api, "contractsGetCount");

const multisigContracts = [
{
id: 533705,
type: "contract",
address: "KT1Mqvf7bnYe4Ty2n7ZbGkdbebCd4WoTJUUp",
kind: "smart_contract",
balance: 0,
creator: { address: "tz1LbSsDSmekew3prdDGx1nS22ie6jjBN6B3" },
numContracts: 0,
activeTokensCount: 0,
tokensCount: 0,
tokenBalancesCount: 0,
tokenTransfersCount: 0,
numDelegations: 0,
numOriginations: 1,
numTransactions: 0,
numReveals: 0,
numMigrations: 0,
transferTicketCount: 0,
increasePaidStorageCount: 0,
eventsCount: 0,
firstActivity: 1636117,
firstActivityTime: "2022-12-09T16:49:25Z",
lastActivity: 1636117,
lastActivityTime: "2022-12-09T16:49:25Z",
storage: {
owner: "tz1LbSsDSmekew3prdDGx1nS22ie6jjBN6B3",
signers: ["tz1LbSsDSmekew3prdDGx1nS22ie6jjBN6B3", "tz1dyX3B1CFYa2DfdFLyPtiJCfQRUgPVME6E"],
metadata: 216412,
threshold: "1",
last_op_id: "0",
pending_ops: 216411,
},
typeHash: 1963879877,
codeHash: -1890025422,
},
{
id: 536908,
type: "contract",
Expand Down Expand Up @@ -124,11 +91,47 @@ const multisigContracts = [
typeHash: 1963879877,
codeHash: -1890025422,
},
{
id: 533705,
type: "contract",
address: "KT1Mqvf7bnYe4Ty2n7ZbGkdbebCd4WoTJUUp",
kind: "smart_contract",
balance: 0,
creator: { address: "tz1LbSsDSmekew3prdDGx1nS22ie6jjBN6B3" },
numContracts: 0,
activeTokensCount: 0,
tokensCount: 0,
tokenBalancesCount: 0,
tokenTransfersCount: 0,
numDelegations: 0,
numOriginations: 1,
numTransactions: 0,
numReveals: 0,
numMigrations: 0,
transferTicketCount: 0,
increasePaidStorageCount: 0,
eventsCount: 0,
firstActivity: 1636117,
firstActivityTime: "2022-12-09T16:49:25Z",
lastActivity: 1636117,
lastActivityTime: "2022-12-09T16:49:25Z",
storage: {
owner: "tz1LbSsDSmekew3prdDGx1nS22ie6jjBN6B3",
signers: ["tz1LbSsDSmekew3prdDGx1nS22ie6jjBN6B3", "tz1dyX3B1CFYa2DfdFLyPtiJCfQRUgPVME6E"],
metadata: 216412,
threshold: "1",
last_op_id: "0",
pending_ops: 216411,
},
typeHash: 1963879877,
codeHash: -1890025422,
},
];

describe("multisig fetch", () => {
const expectedMockedMultisigContracts = [
{
id: 533705,
address: "KT1Mqvf7bnYe4Ty2n7ZbGkdbebCd4WoTJUUp",
storage: {
pending_ops: 216411,
Expand All @@ -137,6 +140,7 @@ describe("multisig fetch", () => {
},
},
{
id: 536908,
address: "KT1VwWbTMRN5uX4bfxCcpJnPP6iAhboqhGZr",
storage: {
pending_ops: 219458,
Expand All @@ -149,6 +153,7 @@ describe("multisig fetch", () => {
},
},
{
id: 537023,
address: "KT1Vdhz4izz7LASWU4tTLu3GBsvhJ8ULSi3G",
storage: {
pending_ops: 219535,
Expand All @@ -160,26 +165,73 @@ describe("multisig fetch", () => {

describe("getAllMultiSigContracts", () => {
it("fetches all multisig contracts", async () => {
mockedContractsGet.mockResolvedValue(multisigContracts as any);
mockedContractsGetCount.mockResolvedValue(multisigContracts.length);
mockedContractsGet.mockResolvedValue(multisigContracts);
const result = await getAllMultisigContracts(GHOSTNET);

expect(mockedContractsGetCount).toHaveBeenCalledTimes(1);
expect(mockedContractsGetCount).toHaveBeenCalledWith(
{
kind: { eq: "smart_contract" },
typeHash: { eq: TYPE_HASH },
codeHash: { eq: CODE_HASH },
},
{ baseUrl: GHOSTNET.tzktApiUrl }
);
expect(mockedContractsGet).toHaveBeenCalledTimes(1);
expect(mockedContractsGet).toHaveBeenCalledWith(
{
kind: { eq: "smart_contract" },
typeHash: { eq: TYPE_HASH },
codeHash: { eq: CODE_HASH },
select: { fields: ["id,address,storage"] },
includeStorage: true,
limit: 10000,
offset: { pg: 0 },
},
{ baseUrl: GHOSTNET.tzktApiUrl }
);
expect(
result.map(({ address, storage: { pending_ops, signers, threshold } }) => ({
result.map(({ id, address, storage: { pending_ops, signers, threshold } }) => ({
id,
address,
storage: { pending_ops, signers, threshold },
}))
).toEqual(expectedMockedMultisigContracts);
});

it("handles pagination", async () => {
mockedContractsGetCount.mockResolvedValue(79123);
mockedContractsGet.mockResolvedValue([]);

await getAllMultisigContracts(GHOSTNET);

expect(mockedContractsGetCount).toHaveBeenCalledTimes(1);
expect(mockedContractsGetCount).toHaveBeenCalledWith(
{
kind: { eq: "smart_contract" },
typeHash: { eq: TYPE_HASH },
codeHash: { eq: CODE_HASH },
},
{ baseUrl: GHOSTNET.tzktApiUrl }
);

expect(mockedContractsGet).toHaveBeenCalledTimes(8);
range(8).forEach(index => {
expect(mockedContractsGet).toHaveBeenCalledWith(
{
kind: { eq: "smart_contract" },
typeHash: { eq: TYPE_HASH },
codeHash: { eq: CODE_HASH },
select: { fields: ["id,address,storage"] },
includeStorage: true,
limit: 10000,
offset: { pg: index },
},
{ baseUrl: GHOSTNET.tzktApiUrl }
);
});
});
});

describe("getExistingContracts", () => {
Expand Down
49 changes: 34 additions & 15 deletions packages/multisig/src/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,46 @@
import { contractsGet } from "@tzkt/sdk-api";
import { contractsGet, contractsGetCount } from "@tzkt/sdk-api";
import { type Network, type RawPkh } from "@umami/tezos";
import { withRateLimit } from "@umami/tzkt";
import axios from "axios";

import { type RawTzktMultisigBigMap, type RawTzktMultisigContract } from "./types";

Check warning on line 6 in packages/multisig/src/fetch.ts

View workflow job for this annotation

GitHub Actions / test

There should be at least one empty line between import groups

Check warning on line 6 in packages/multisig/src/fetch.ts

View workflow job for this annotation

GitHub Actions / test

`./types` import should occur after import of `lodash/sortBy`
import range from "lodash/range";
import sortBy from "lodash/sortBy";

export const TYPE_HASH = 1963879877;
export const CODE_HASH = -1890025422;
const MULTISIG_QUERY = {
kind: { eq: "smart_contract" as const },
typeHash: { eq: TYPE_HASH },
codeHash: { eq: CODE_HASH },
};
const LIMIT = 10000;

export const getAllMultisigContracts = async (network: Network) =>
withRateLimit(() =>
contractsGet(
{
typeHash: { eq: TYPE_HASH },
codeHash: { eq: CODE_HASH },
includeStorage: true,
limit: 10000,
},
{
baseUrl: network.tzktApiUrl,
}
export const getAllMultisigContracts = async (network: Network) => {
const count = await withRateLimit(() =>
contractsGetCount(MULTISIG_QUERY as any, { baseUrl: network.tzktApiUrl })
);

const batches = await Promise.all(
range(Math.ceil(count / LIMIT)).map(index =>
withRateLimit(() =>
contractsGet(
{
...MULTISIG_QUERY,
includeStorage: true,
limit: LIMIT,
offset: { pg: index },
select: { fields: [["id", "address", "storage"].join(",")] },
},
{
baseUrl: network.tzktApiUrl,
}
)
)
)
) as Promise<RawTzktMultisigContract[]>;
);
return sortBy(batches.flat(), "id") as RawTzktMultisigContract[];
};

/**
* Returns existing addresses for the given contract addresses list & the given network.
Expand All @@ -36,7 +55,7 @@ export const getExistingContracts = (pkhs: RawPkh[], network: Network): Promise<
{
address: { in: [pkhs.join(",")] },
select: { fields: ["address"] },
limit: Math.min(10000, pkhs.length),
limit: Math.min(LIMIT, pkhs.length),
},
{
baseUrl: network.tzktApiUrl,
Expand Down
11 changes: 8 additions & 3 deletions packages/multisig/src/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ import {
getRelevantMultisigContracts,
parseMultisig,
} from "./helpers";
import { type RawTzktMultisigContract } from "./types";

const mockedAxios = jest.spyOn(axios, "get");

const mockedContractsGet = jest.spyOn(api, "contractsGet");
const mockedContractsGetCount = jest.spyOn(api, "contractsGetCount");

const tzktGetSameMultisigsResponse: RawTzktMultisigContract[] = [
const tzktGetSameMultisigsResponse = [
{
id: 1,
type: "contract",
address: mockContractAddress(0).pkh,
storage: { threshold: "2", pending_ops: 0, signers: [mockImplicitAddress(0).pkh] },
},
{
id: 2,
type: "contract",
address: mockContractAddress(2).pkh,
storage: { threshold: "2", pending_ops: 1, signers: [mockImplicitAddress(2).pkh] },
},
Expand All @@ -35,7 +39,8 @@ describe("multisig helpers", () => {
describe.each(DefaultNetworks)("on $name", network => {
describe("getRelevantMultisigContracts", () => {
it("fetches multisig contracts", async () => {
mockedContractsGet.mockResolvedValue(tzktGetSameMultisigsResponse as any);
mockedContractsGetCount.mockResolvedValue(tzktGetSameMultisigsResponse.length);
mockedContractsGet.mockResolvedValue(tzktGetSameMultisigsResponse);

const result = await getRelevantMultisigContracts(
new Set([mockImplicitAddress(0).pkh]),
Expand Down
1 change: 1 addition & 0 deletions packages/multisig/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type Multisig = {
export type MultisigPendingOperations = Record<BigmapId, MultisigOperation[] | undefined>;

export type RawTzktMultisigContract = {
id: number;
address: string;
storage: {
signers: string[];
Expand Down

0 comments on commit c9f0144

Please sign in to comment.