Skip to content

Commit

Permalink
feat: add migration record tracking (#16)
Browse files Browse the repository at this point in the history
* feat: add  migration record tracking

* chore: update default db settings
  • Loading branch information
maxlm-devico authored Oct 10, 2024
1 parent 606b453 commit 0ec07d0
Show file tree
Hide file tree
Showing 11 changed files with 753 additions and 5 deletions.
9 changes: 9 additions & 0 deletions paymaster/config/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const NODE_ENV = process.env.NODE_ENV || "local";
export const DB_DATABASE = process.env.DB_DATABASE || "gas-tank";
export const DB_HOST = process.env.DB_HOST || "host.docker.internal";
export const DB_PASSWORD = process.env.DB_PASSWORD || "";
export const DB_PORT = Number(process.env.DB_PORT) || 5432;
export const DB_USERNAME = process.env.DB_USERNAME || "postgres";
export const DB_SSL_MODE = process.env.DB_SSL_MODE
? (process.env.DB_SSL_MODE || "").toLowerCase() === "true"
: NODE_ENV !== "local";
26 changes: 26 additions & 0 deletions paymaster/db/entity/MigrationTracking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity({
name: "migration_tracking",
})
export class MigrationTracking extends BaseEntity {
@PrimaryGeneratedColumn("increment")
id!: number;

@Column({ name: "transaction_hash", type: "text" })
transactionHash!: string;

@Column({ name: "wallet_address", type: "text" })
walletAddress!: string;

@Column({
nullable: true,
type: "text",
})
token!: string;

@Column({
type: "text",
})
chain!: string;
}
43 changes: 43 additions & 0 deletions paymaster/db/paymaster-data-source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { DataSource } from "typeorm";
import {
DB_DATABASE,
DB_HOST,
DB_PASSWORD,
DB_PORT,
DB_USERNAME,
DB_SSL_MODE,
NODE_ENV,
} from "../config/db";
import { MigrationTracking } from "./entity/MigrationTracking";

const PaymasterDataSource = new DataSource({
type: "postgres",
host: DB_HOST,
port: DB_PORT,
username: DB_USERNAME,
password: DB_PASSWORD,
database: DB_DATABASE,
synchronize: true,
ssl: DB_SSL_MODE
? process.env.CA_CERT
? {
rejectUnauthorized: true,
ca: process.env.CA_CERT,
}
: {
rejectUnauthorized: false,
}
: false,
logging: false,
entities: [MigrationTracking],
migrations:
NODE_ENV === "local"
? ["src/migrations/**/*.ts"]
: ["dist/migrations/**/*.js"],
subscribers:
NODE_ENV === "local"
? ["src/subscriber/**/*.ts"]
: ["dist/subscriber/**/*.js"],
});

export { PaymasterDataSource };
5 changes: 5 additions & 0 deletions paymaster/migration/MigrationContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import {
import { xdefiToCtrlMigrationAbi } from "../data/abi/xdefiToCtrlMigrationAbi";
import { erc20Abi } from "../data/abi/erc20Abi";
import { getMnemonic } from "./getMnemonic";
import { PaymasterDataSource } from "../db/paymaster-data-source";
import { DataSource } from "typeorm";

export type MigrationContext = {
migrationContract: Contract;
xdefiContract: Contract;
vXdefiContract: Contract;
provider: JsonRpcProvider;
wallet: Wallet;
dataSource: DataSource;
getTokenContract: (tokenAddress: string) => Contract;
};

Expand All @@ -24,6 +27,7 @@ async function createMigrationContext(): Promise<MigrationContext> {
const provider = new JsonRpcProvider(PROVIDER_RPC_URL);

const mnemonic = await getMnemonic();
const dataSource = await PaymasterDataSource.initialize();
const wallet = new Wallet(Wallet.fromPhrase(mnemonic).privateKey, provider);

const migrationContract = new Contract(
Expand All @@ -42,6 +46,7 @@ async function createMigrationContext(): Promise<MigrationContext> {
vXdefiContract,
provider,
wallet,
dataSource,
getTokenContract(tokenAddress) {
switch (tokenAddress.toLowerCase()) {
case XDEFI_TOKEN_ADDRESS.toLowerCase():
Expand Down
21 changes: 21 additions & 0 deletions paymaster/migration/saveMigrationRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { QueryRunner } from "typeorm";
import { MigrationTracking } from "../db/entity/MigrationTracking";

export type SaveMigrationRecordParams = {
user: string;
tokenAddress: string;
txHash: string;
};
export async function saveMigrationRecord(
queryRunner: QueryRunner,
{ user, tokenAddress, txHash }: SaveMigrationRecordParams
) {
const trackRecord = queryRunner.manager.create(MigrationTracking, {
chain: "ethereum",
token: tokenAddress.toLowerCase(),
transactionHash: txHash,
walletAddress: user.toLowerCase(),
});

await queryRunner.manager.save(trackRecord);
}
19 changes: 19 additions & 0 deletions paymaster/migration/validation/isAlreadyMigrated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { QueryRunner } from "typeorm";
import { MigrationTracking } from "../../db/entity/MigrationTracking";

export type IsAlreadyMigratedParams = {
user: string;
tokenAddress: string;
};
export async function isAlreadyMigrated(
queryRunner: QueryRunner,
{ user, tokenAddress }: IsAlreadyMigratedParams
) {
const trackRecord = await queryRunner.manager.findOneBy(MigrationTracking, {
chain: "ethereum",
token: tokenAddress.toLowerCase(),
walletAddress: user.toLowerCase(),
});

return Boolean(trackRecord);
}
2 changes: 2 additions & 0 deletions paymaster/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"@aws-sdk/client-kms": "^3.621.0",
"axios": "^1.7.4",
"ethers": "^6.13.1",
"pg": "^8.13.0",
"typeorm": "^0.3.20",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
31 changes: 31 additions & 0 deletions paymaster/paymaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { migrateGaslessFrom } from "./migration/migrateGasless";
import { getMigrationContext } from "./migration/MigrationContext";
import { isMigrationAllowed } from "./migration/validation/isMigrationAllowed";
import { migrationRequestSchema } from "./migration/validation/migrationRequestSchema";
import { isAlreadyMigrated } from "./migration/validation/isAlreadyMigrated";
import { saveMigrationRecord } from "./migration/saveMigrationRecord";
import { resolveWithTimeout } from "./migration/utils";

const headers = {
Expand Down Expand Up @@ -36,6 +38,8 @@ export const handler = async (

const migrationContext = await getMigrationContext();

const queryRunner = migrationContext.dataSource.createQueryRunner();

const [isAllowed, message] = await isMigrationAllowed(migrationContext, {
user,
tokenAddress,
Expand All @@ -52,6 +56,21 @@ export const handler = async (
};
}

const isMigratedBefore = await isAlreadyMigrated(queryRunner, {
user,
tokenAddress,
});

if (isMigratedBefore) {
return {
statusCode: 400,
headers,
body: JSON.stringify({
message: `address ${user} alreasy performed migration of ${tokenAddress} token`,
}),
};
}

const tokenContract = migrationContext.getTokenContract(tokenAddress);

const userAmount = (await tokenContract.balanceOf(user)) as bigint;
Expand Down Expand Up @@ -94,6 +113,18 @@ export const handler = async (
};
}

try {
await saveMigrationRecord(queryRunner, {
user,
tokenAddress,
txHash: maybeReceipt?.hash || "",
});
} catch (e) {
console.error(e);
} finally {
await queryRunner.release();
}

return {
statusCode: 200,
headers,
Expand Down
47 changes: 46 additions & 1 deletion paymaster/test/paymaster.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ import {
} from "../migration/MigrationContext";
import { XDEFI_VALUE_THRESHOLD } from "../config/config";
import { migrationRequestSchema } from "../migration/validation/migrationRequestSchema";
import { isAlreadyMigrated } from "../migration/validation/isAlreadyMigrated";
import { saveMigrationRecord } from "../migration/saveMigrationRecord";

vi.mock("../migration/MigrationContext.ts", () => ({
getMigrationContext: vi.fn(),
getMigrationContext: vi.fn().mockResolvedValue({
dataSource: {
createQueryRunner: vi
.fn()
.mockReturnValue({ release: vi.fn().mockResolvedValue(undefined) }),
},
}),
initMigrationContext: vi.fn(),
}));

Expand All @@ -21,6 +29,23 @@ vi.mock("../migration/validation/migrationRequestSchema.ts", () => ({
},
}));

vi.mock("../db/paymaster-data-source.ts", () => ({
PaymasterDataSource: {
initialize: vi.fn(),
createQueryRunner: vi
.fn()
.mockReturnValue({ release: vi.fn().mockResolvedValue(undefined) }),
},
}));

vi.mock("../migration/validation/isAlreadyMigrated", () => ({
isAlreadyMigrated: vi.fn().mockResolvedValue(false),
}));

vi.mock("../migration/saveMigrationRecord", () => ({
saveMigrationRecord: vi.fn().mockResolvedValue(undefined),
}));

vi.mock("../migration/getTokenHolding.ts", () => ({
getTokenHolding: vi.fn(),
}));
Expand Down Expand Up @@ -150,6 +175,11 @@ describe("Paymaster handler", () => {
}),
provider: vi.fn(),
wallet: vi.fn(),
dataSource: {
createQueryRunner: vi
.fn()
.mockReturnValue({ release: vi.fn().mockResolvedValue(undefined) }),
},
} as any as MigrationContext);
});

Expand Down Expand Up @@ -204,6 +234,11 @@ describe("Paymaster handler", () => {
}),
provider: vi.fn(),
wallet: vi.fn(),
dataSource: {
createQueryRunner: vi
.fn()
.mockReturnValue({ release: vi.fn().mockResolvedValue(undefined) }),
},
} as any as MigrationContext);
});

Expand Down Expand Up @@ -261,6 +296,11 @@ describe("Paymaster handler", () => {
}),
provider: vi.fn(),
wallet: vi.fn(),
dataSource: {
createQueryRunner: vi
.fn()
.mockReturnValue({ release: vi.fn().mockResolvedValue(undefined) }),
},
} as any as MigrationContext);
});

Expand Down Expand Up @@ -325,6 +365,11 @@ describe("Paymaster handler", () => {
},
provider: vi.fn(),
wallet: vi.fn(),
dataSource: {
createQueryRunner: vi
.fn()
.mockReturnValue({ release: vi.fn().mockResolvedValue(undefined) }),
},
} as any as MigrationContext);
});

Expand Down
4 changes: 3 additions & 1 deletion paymaster/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Loading

0 comments on commit 0ec07d0

Please sign in to comment.