Skip to content

Commit

Permalink
fix: unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hhio618 committed Jan 10, 2025
1 parent 82b5ae5 commit 81aa774
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 49 deletions.
23 changes: 12 additions & 11 deletions src/helpers/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ import { RPCHandler, HandlerConstructorConfig, NetworkId } from "@ubiquity-dao/r
import { Context } from "@ubiquity-os/permit-generation";
import { ethers, utils } from "ethers";

// Required ERC20 ABI functions
export const ERC20_ABI = [
"function symbol() view returns (string)",
"function decimals() public view returns (uint8)",
"function balanceOf(address) view returns (uint256)",
"function transfer(address,uint256) public returns (bool)",
];

/**
* Returns the funding wallet
* @param privateKey of the funding wallet
* @param provider ethers.Provider
* @returns the funding wallet
*/
async function getFundingWallet(privateKey: string, provider: ethers.providers.Provider) {
export async function getFundingWallet(privateKey: string, provider: ethers.providers.Provider) {
try {
return new ethers.Wallet(privateKey, provider);
} catch (error) {
Expand All @@ -24,14 +32,7 @@ async function getFundingWallet(privateKey: string, provider: ethers.providers.P
* @returns ERC20 token contract
*/

async function getErc20TokenContract(networkId: number, tokenAddress: string) {
const abi = [
"function symbol() view returns (string)",
"function decimals() public view returns (uint8)",
"function balanceOf(address) view returns (uint256)",
"function transfer(address,uint256) public returns (bool)",
];

export async function getErc20TokenContract(networkId: number, tokenAddress: string) {
// get fastest RPC
const config: HandlerConstructorConfig = {
networkName: null,
Expand All @@ -52,7 +53,7 @@ async function getErc20TokenContract(networkId: number, tokenAddress: string) {
const handler = new RPCHandler(config);
const provider = await handler.getFastestRpcProvider();

return new ethers.Contract(tokenAddress, abi, provider);
return new ethers.Contract(tokenAddress, ERC20_ABI, provider);
}
/**
* Returns ERC20 token symbol
Expand All @@ -70,7 +71,7 @@ export async function getErc20TokenSymbol(networkId: number, tokenAddress: strin
* @param tokenAddress ERC20 token address
* @returns ERC20 token decimals
*/
async function getErc20TokenDecimals(networkId: number, tokenAddress: string) {
export async function getErc20TokenDecimals(networkId: number, tokenAddress: string) {
return await (await getErc20TokenContract(networkId, tokenAddress)).decimals();
}

Expand Down
1 change: 1 addition & 0 deletions tests/__mocks__/results/valid-configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
},
"erc20RewardToken": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
"evmNetworkId": 100,
"autoTransferMode": false,
"evmPrivateEncrypted": "qGslGsT9bfY0C3uc_utvFhBN_Zwggf0sONEFOfF67E_gWDXqnV3qC-LnGj2ufIHJwdHxFLz3VVzup2MrGtFtHhZ2WZZvq_8NQi48LFbr5b6OIxL-vOXooAyQYfb2mjLmcsYaxXc5eu1mUfO9rfENSAw9dFeWfi9VKQ",
"incentives": {
"collaboratorOnlyPaymentInvocation": true,
Expand Down
54 changes: 53 additions & 1 deletion tests/helpers/web3.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { getErc20TokenSymbol } from "../../src/helpers/web3";
import { BigNumber } from "ethers";
import {
getErc20TokenSymbol,
getErc20TokenDecimals,
getFundingWalletBalance,
getFundingWallet,
getErc20TokenContract,
ERC20_ABI,
} from "../../src/helpers/web3";
import { Interface } from "ethers/lib/utils";

describe("web3.ts", () => {
describe("getERC20TokenSymbol()", () => {
Expand All @@ -9,4 +18,47 @@ describe("web3.ts", () => {
expect(tokenSymbol).toEqual("WXDAI");
}, 120000);
});
describe("getErc20TokenDecimals()", () => {
it("Should return ERC20 token decimals", async () => {
const networkId = 100; // gnosis
const tokenAddress = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"; // WXDAI
const tokenDecimals = await getErc20TokenDecimals(networkId, tokenAddress);
expect(tokenDecimals).toEqual(18);
}, 120000);
});
describe("getFundingWalletBalance()", () => {
it("Should return ERC20 token balance of the funding wallet", async () => {
const networkId = 100; // gnosis
const tokenAddress = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"; // WXDAI
const tokenBalance: BigNumber = await getFundingWalletBalance(
networkId,
tokenAddress,
"100958e64966448354216e91d4d4b9418c3fa0cb0a21b935535ced1df8145a0e"
);
expect(tokenBalance.isZero()).toEqual(true);
}, 120000);
});
describe("getFundingWallet()", () => {
it("Should return ERC20 token decimals", async () => {
const networkId = 100; // gnosis
const tokenAddress = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"; // WXDAI
const contract = await getErc20TokenContract(networkId, tokenAddress);
const fundingWallet = await getFundingWallet(
"100958e64966448354216e91d4d4b9418c3fa0cb0a21b935535ced1df8145a0e",
contract.provider
);
const fundingWalledAddress = await fundingWallet.getAddress();
expect(fundingWalledAddress.toLowerCase()).toEqual("0x94d7a85efef179560f9b821cadd20056600fdb9d");
}, 120000);
});

describe("getErc20TokenContract()", () => {
it("Should return ERC20 token contract", async () => {
const networkId = 100; // gnosis
const tokenAddress = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"; // WXDAI
const contract = await getErc20TokenContract(networkId, tokenAddress);
expect(contract.address).toEqual(tokenAddress);
expect(contract.interface).toEqual(new Interface(ERC20_ABI));
}, 120000);
});
});
52 changes: 26 additions & 26 deletions tests/parser/permit-generation-module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ const resultOriginal: Result = {
},
};

const { PermitGenerationModule } = await import("../../src/parser/permit-generation-module");
const { PaymentModule } = await import("../../src/parser/payment-module");

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe("permit-generation-module.ts", () => {
describe("payment-module.ts", () => {
describe("applyFees()", () => {
beforeEach(() => {
ctx.env.PERMIT_FEE_RATE = "10";
Expand All @@ -125,19 +125,19 @@ describe("permit-generation-module.ts", () => {

it("Should not apply fees if PERMIT_FEE_RATE is empty", async () => {
ctx.env.PERMIT_FEE_RATE = "";
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");
await permitGenerationModule._applyFees(resultOriginal, WXDAI_ADDRESS);
await paymentModule._applyFees(resultOriginal, WXDAI_ADDRESS);
const logCallArgs = spyConsoleLog.mock.calls.map((call) => call[0]);
expect(logCallArgs[0]).toMatch(/.*PERMIT_FEE_RATE is not set, skipping permit fee generation/);
spyConsoleLog.mockReset();
});

it("Should not apply fees if PERMIT_FEE_RATE is 0", async () => {
ctx.env.PERMIT_FEE_RATE = "0";
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");
await permitGenerationModule._applyFees(resultOriginal, WXDAI_ADDRESS);
await paymentModule._applyFees(resultOriginal, WXDAI_ADDRESS);
const logCallArgs = spyConsoleLog.mock.calls.map((call) => call[0]);
expect(logCallArgs[0]).toMatch(/.*PERMIT_FEE_RATE is not set, skipping permit fee generation/);
spyConsoleLog.mockReset();
Expand All @@ -146,18 +146,18 @@ describe("permit-generation-module.ts", () => {
it("Should not apply fees if PERMIT_TREASURY_GITHUB_USERNAME is empty", async () => {
process.env.PERMIT_TREASURY_GITHUB_USERNAME = "";
ctx.env.PERMIT_TREASURY_GITHUB_USERNAME = "";
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");
await permitGenerationModule._applyFees(resultOriginal, WXDAI_ADDRESS);
await paymentModule._applyFees(resultOriginal, WXDAI_ADDRESS);
const logCallArgs = spyConsoleLog.mock.calls.map((call) => call[0]);
expect(logCallArgs[0]).toMatch(/.*PERMIT_TREASURY_GITHUB_USERNAME is not set, skipping permit fee generation/);
spyConsoleLog.mockReset();
});

it("Should not apply fees if ERC20 reward token is included in PERMIT_ERC20_TOKENS_NO_FEE_WHITELIST", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");
await permitGenerationModule._applyFees(resultOriginal, DOLLAR_ADDRESS);
await paymentModule._applyFees(resultOriginal, DOLLAR_ADDRESS);
const logCallArgs = spyConsoleLog.mock.calls.map((call) => call[0]);
expect(logCallArgs[0]).toMatch(
new RegExp(`.*Token address ${DOLLAR_ADDRESS} is whitelisted to be fee free, skipping permit fee generation`)
Expand All @@ -166,8 +166,8 @@ describe("permit-generation-module.ts", () => {
});

it("Should apply fees", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const resultAfterFees = await permitGenerationModule._applyFees(resultOriginal, WXDAI_ADDRESS);
const paymentModule = new PaymentModule(ctx);
const resultAfterFees = await paymentModule._applyFees(resultOriginal, WXDAI_ADDRESS);

// check that 10% fee is subtracted from rewards
expect(resultAfterFees["user1"].total).toEqual(90);
Expand All @@ -189,7 +189,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return false if private key could not be decrypted", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "warn");

// format: "PRIVATE_KEY"
Expand All @@ -198,7 +198,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 1;
const githubContextRepositoryId = 2;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand All @@ -212,7 +212,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return false if private key is used in unallowed organization", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");

// format: "PRIVATE_KEY:GITHUB_ORGANIZATION_ID"
Expand All @@ -222,7 +222,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 99;
const githubContextRepositoryId = 2;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand All @@ -236,7 +236,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return true if private key is used in allowed organization", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);

// format: "PRIVATE_KEY:GITHUB_ORGANIZATION_ID"
// encrypted value: "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80:1"
Expand All @@ -245,7 +245,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 1;
const githubContextRepositoryId = 2;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand All @@ -256,7 +256,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return false if private key is used in un-allowed organization and allowed repository", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");

// format: "PRIVATE_KEY:GITHUB_ORGANIZATION_ID:GITHUB_REPOSITORY_ID"
Expand All @@ -266,7 +266,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 99;
const githubContextRepositoryId = 2;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand All @@ -282,7 +282,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return false if private key is used in allowed organization and unallowed repository", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "info");

// format: "PRIVATE_KEY:GITHUB_ORGANIZATION_ID:GITHUB_REPOSITORY_ID"
Expand All @@ -292,7 +292,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 1;
const githubContextRepositoryId = 99;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand All @@ -308,7 +308,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return true if private key is used in allowed organization and repository", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);

// format: "PRIVATE_KEY:GITHUB_ORGANIZATION_ID:GITHUB_REPOSITORY_ID"
// encrypted value: "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80:1:2"
Expand All @@ -317,7 +317,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 1;
const githubContextRepositoryId = 2;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand All @@ -328,7 +328,7 @@ describe("permit-generation-module.ts", () => {
});

it("Should return false if private key format is invalid", async () => {
const permitGenerationModule = new PermitGenerationModule(ctx);
const paymentModule = new PaymentModule(ctx);
const spyConsoleLog = jest.spyOn(console, "warn");

// format: "PRIVATE_KEY:GITHUB_ORGANIZATION_ID:GITHUB_REPOSITORY_ID"
Expand All @@ -338,7 +338,7 @@ describe("permit-generation-module.ts", () => {
const githubContextOrganizationId = 1;
const githubContextRepositoryId = 2;

const isAllowed = await permitGenerationModule._isPrivateKeyAllowed(
const isAllowed = await paymentModule._isPrivateKeyAllowed(
privateKeyEncrypted,
githubContextOrganizationId,
githubContextRepositoryId,
Expand Down
Loading

0 comments on commit 81aa774

Please sign in to comment.