Skip to content

Commit

Permalink
Merge pull request #17 from rndquu/feat/custom-reward-token
Browse files Browse the repository at this point in the history
feat: add custom reward token to permit
  • Loading branch information
0x4007 authored Jun 17, 2024
2 parents e2633b3 + 74ac030 commit f86cb3c
Show file tree
Hide file tree
Showing 8 changed files with 10,491 additions and 7,483 deletions.
23 changes: 17 additions & 6 deletions src/handlers/generate-erc20-permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export interface Payload {
userId: number;
}

export async function generateErc20PermitSignature(payload: Payload, username: string, amount: number): Promise<PermitReward>;
export async function generateErc20PermitSignature(context: Context, username: string, amount: number): Promise<PermitReward>;
export async function generateErc20PermitSignature(contextOrPayload: Context | Payload, username: string, amount: number): Promise<PermitReward> {
export async function generateErc20PermitSignature(payload: Payload, username: string, amount: number, tokenAddress: string): Promise<PermitReward>;
export async function generateErc20PermitSignature(context: Context, username: string, amount: number, tokenAddress: string): Promise<PermitReward>;
export async function generateErc20PermitSignature(contextOrPayload: Context | Payload, username: string, amount: number, tokenAddress: string): Promise<PermitReward> {
let _logger: Logger;
const _username = username;
let _walletAddress: string | null | undefined;
Expand Down Expand Up @@ -63,7 +63,7 @@ export async function generateErc20PermitSignature(contextOrPayload: Context | P
throw new Error(errorMessage);
}

const { rpc, token, decimals } = getPayoutConfigByNetworkId(_evmNetworkId);
const { rpc } = getPayoutConfigByNetworkId(_evmNetworkId);
const { privateKey } = await decryptKeys(_evmPrivateEncrypted);
if (!privateKey) {
const errorMessage = "Private key is not defined";
Expand All @@ -73,6 +73,7 @@ export async function generateErc20PermitSignature(contextOrPayload: Context | P

let provider;
let adminWallet;
let tokenDecimals;
try {
provider = new ethers.JsonRpcProvider(rpc);
} catch (error) {
Expand All @@ -89,10 +90,20 @@ export async function generateErc20PermitSignature(contextOrPayload: Context | P
throw new Error(errorMessage);
}

try {
const erc20Abi = ["function decimals() public view returns (uint8)"];
const tokenContract = new ethers.Contract(tokenAddress, erc20Abi, provider);
tokenDecimals = await tokenContract.decimals();
} catch (error) {
const errorMessage = `Failed to get token decimals for token: ${tokenAddress}`;
_logger.debug(errorMessage);
throw new Error(errorMessage);
}

const permitTransferFromData: PermitTransferFrom = {
permitted: {
token: token,
amount: parseUnits(amount.toString(), decimals),
token: tokenAddress,
amount: parseUnits(amount.toString(), tokenDecimals),
},
spender: _walletAddress,
nonce: BigInt(keccak256(toUtf8Bytes(`${_userId}-${_issueId}`))),
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/generate-payout-permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ export async function generatePayoutPermit(context: Context, permitRequests: Per
const permits: PermitReward[] = [];

for (const permitRequest of permitRequests) {
const { type, amount, username, contributionType } = permitRequest;
const { type, amount, username, contributionType, tokenAddress } = permitRequest;

let permit: PermitReward;
switch (type) {
case "ERC20":
permit = await generateErc20PermitSignature(context, username, amount);
permit = await generateErc20PermitSignature(context, username, amount, tokenAddress);
break;
case "ERC721":
permit = await generateErc721PermitSignature(context, username, contributionType);
Expand Down
1 change: 1 addition & 0 deletions src/types/plugin-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const permitRequestSchema = T.Object({
username: T.String(),
amount: T.Number(),
contributionType: T.String(),
tokenAddress: T.String(),
});

export type PermitRequest = StaticDecode<typeof permitRequestSchema>;
Expand Down
8 changes: 1 addition & 7 deletions src/utils/payoutConfigByNetworkId.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
// available tokens for payouts
export const PAYMENT_TOKEN_PER_NETWORK: Record<string, { rpc: string; token: string; decimals: number }> = {
export const PAYMENT_TOKEN_PER_NETWORK: Record<string, { rpc: string; }> = {
"1": {
rpc: "https://rpc.mevblocker.io",
token: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI
decimals: 18,
},
"100": {
rpc: "https://rpc.gnosis.gateway.fm",
token: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // WXDAI
decimals: 18,
},
"31337": {
rpc: "http://localhost:8545",
token: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // WXDAI
decimals: 18,
},
};

Expand Down
1 change: 1 addition & 0 deletions tests/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { jest } from "@jest/globals";

export const NFT_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000000003";
export const SPENDER = "123";
export const ERC20_REWARD_TOKEN_ADDRESS = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"; // WXDAI

export const WALLET_ADDRESS = "0xefC0e701A824943b469a694aC564Aa1efF7Ab7dd";

Expand Down
10 changes: 5 additions & 5 deletions tests/generate-erc20-permit.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it, beforeEach, jest } from "@jest/globals";
import { generateErc20PermitSignature } from "../src";
import { Context } from "../src/types/context";
import { SPENDER, mockContext } from "./constants";
import { describe, expect, it, beforeEach, jest } from "@jest/globals";
import { SPENDER, mockContext, ERC20_REWARD_TOKEN_ADDRESS } from "./constants";

describe("generateErc20PermitSignature", () => {
let context: Context;
Expand Down Expand Up @@ -66,7 +66,7 @@ describe("generateErc20PermitSignature", () => {

context.config.evmPrivateEncrypted = cypherText;

const result = await generateErc20PermitSignature(context, SPENDER, amount);
const result = await generateErc20PermitSignature(context, SPENDER, amount, ERC20_REWARD_TOKEN_ADDRESS);

expect(result).toBeDefined();
expect(result).not.toContain("Permit not generated");
Expand All @@ -77,7 +77,7 @@ describe("generateErc20PermitSignature", () => {
it("should throw error when evmPrivateEncrypted is not defined", async () => {
const amount = 0;

await expect(generateErc20PermitSignature(context, SPENDER, amount)).rejects.toThrow("Private key is not defined");
await expect(generateErc20PermitSignature(context, SPENDER, amount, ERC20_REWARD_TOKEN_ADDRESS)).rejects.toThrow("Private key is not defined");
expect(context.logger.fatal).toHaveBeenCalledWith("Private key is not defined");
});

Expand All @@ -88,7 +88,7 @@ describe("generateErc20PermitSignature", () => {
(context.adapters.supabase.wallet.getWalletByUserId as jest.Mock).mockReturnValue(null);

await expect(async () => {
await generateErc20PermitSignature(context, SPENDER, amount);
await generateErc20PermitSignature(context, SPENDER, amount, ERC20_REWARD_TOKEN_ADDRESS);
}).rejects.toThrow();

expect(context.logger.error).toHaveBeenCalledWith("ERC20 Permit generation error: Wallet not found");
Expand Down
2 changes: 2 additions & 0 deletions tests/generate-payout-permit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ describe("generatePayoutPermit", () => {
amount: 100,
username: "123",
contributionType: "ISSUE",
tokenAddress: "TOKEN_ADDRESS",
},
{
type: "ERC20",
amount: 100,
username: "123",
contributionType: "ISSUE",
tokenAddress: "TOKEN_ADDRESS",
},
]);

Expand Down
Loading

0 comments on commit f86cb3c

Please sign in to comment.