Skip to content

Commit

Permalink
fix: removed provider permit generation
Browse files Browse the repository at this point in the history
  • Loading branch information
gentlementlegen committed Feb 19, 2025
1 parent 4b91261 commit d6bb847
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 23 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"js-tiktoken": "1.0.15",
"jsdom": "24.0.0",
"markdown-it": "14.1.0",
"ms": "^2.1.3",
"minimatch": "^10.0.1",
"ms": "^2.1.3",
"openai": "4.56.0",
"yaml": "^2.6.1"
},
Expand Down Expand Up @@ -81,8 +81,8 @@
"prettier": "3.3.3",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"ts-node": "10.9.2",
"ts-jest": "^29.2.5",
"ts-node": "10.9.2",
"typescript": "^5.6.3",
"typescript-eslint": "^8.13.0"
},
Expand Down
129 changes: 129 additions & 0 deletions src/helpers/permit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { createAdapters, decrypt, parseDecryptedPrivateKey } from "@ubiquity-os/permit-generation";
import { ethers, utils } from "ethers";
import { ContextPlugin } from "../types/plugin-input";

type PermitDetails = {
token: string; // address
amount: ethers.BigNumberish; // uint160
expiration: string; // uint48
nonce: ethers.BigNumberish; // uint48
};

type PermitSingle = {
details: PermitDetails;
spender: string; // address
sigDeadline: ethers.BigNumberish; // uint256
};

// These are the EIP-712 type definitions from Uniswap's Permit2.
const permit2Types = {
PermitSingle: [
{ name: "details", type: "PermitDetails" },
{ name: "spender", type: "address" },
{ name: "sigDeadline", type: "uint256" },
],
PermitDetails: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint160" },
{ name: "expiration", type: "uint48" },
{ name: "nonce", type: "uint48" },
],
};

/**
* signPermit2() generates an EIP-712 signature for Uniswap's Permit2.
*
* @param privateKey the private key of the signer
* @param permit2Address the deployed Permit2 contract address
* @param chainId the chain ID
* @param permitSingle the permit data
* @returns the signature string
*/
export async function signPermit2(
privateKey: string,
permit2Address: string,
chainId: number,
permitSingle: PermitSingle
): Promise<string> {
const domainData = {
name: "Permit2",
version: "1",
chainId,
verifyingContract: permit2Address,
};

const wallet = new ethers.Wallet(privateKey);
return wallet._signTypedData(domainData, permit2Types, permitSingle);
}

async function getPrivateKey(evmPrivateEncrypted: string) {
try {
const privateKeyDecrypted = await decrypt(evmPrivateEncrypted, String(process.env.X25519_PRIVATE_KEY));
const privateKeyParsed = parseDecryptedPrivateKey(privateKeyDecrypted);
const privateKey = privateKeyParsed.privateKey;
if (!privateKey) throw new Error("Private key is not defined");
return privateKey;
} catch (error) {
const errorMessage = `Failed to decrypt a private key: ${error}`;
throw new Error(errorMessage);
}
}

/**
* Generates a claim base64 encoded compatible with pay.ubq.fi
*/
export async function generatePermitUrlPayload(
context: ContextPlugin,
userName: string,
chainId: number,
amount: number,
erc20RewardToken: string,
adapters: ReturnType<typeof createAdapters>
) {
const privateKey = await getPrivateKey(context.config.evmPrivateEncrypted); // Replace with your private key
const permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // Deployed Permit2 contract
const convertedAmount = utils.parseUnits(amount.toString(), 18);
const deadline = Date.now().toString();
const spenderWallet = new ethers.Wallet(privateKey);
const { data: userData } = await context.octokit.rest.users.getByUsername({ username: userName });

if (!userData) {
throw new Error(`GitHub user was not found for id ${userName}`);
}

// Had to truncate the nonce to fit in an uint48
const nonce =
BigInt(utils.keccak256(utils.toUtf8Bytes(`${userData.id}-${context.payload.issue.node_id}`))) % BigInt(2 ** 48);
const walletAddress = await adapters.supabase.wallet.getWalletByUserId(userData.id);
const permitSingle: PermitSingle = {
details: {
token: erc20RewardToken,
amount: convertedAmount, // 1 token with 18 decimals
expiration: deadline, // Unix timestamp
nonce: nonce.toString(),
},
spender: spenderWallet.address,
sigDeadline: deadline, // Unix timestamp
};
const signature = await signPermit2(privateKey, permit2Address, chainId, permitSingle);
const permit = {
type: "erc20-permit",
permit: {
permitted: {
token: erc20RewardToken,
amount: convertedAmount,
},
nonce: nonce.toString(),
deadline: deadline,
},
transferDetails: {
to: walletAddress,
requestedAmount: convertedAmount,
},
owner: spenderWallet.address,
signature: signature,
networkId: chainId,
};

return Buffer.from(JSON.stringify([permit])).toString("base64");
}
36 changes: 15 additions & 21 deletions src/parser/permit-generation-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import {
createAdapters,
Database,
decrypt,
encodePermits,
generatePayoutPermit,
parseDecryptedPrivateKey,
PermitReward,
SupportedEvents,
Expand All @@ -19,12 +17,13 @@ import {
PermitGenerationConfiguration,
permitGenerationConfigurationType,
} from "../configuration/permit-generation-configuration";
import { isAdmin, isCollaborative } from "../helpers/checkers";
import { generatePermitUrlPayload } from "../helpers/permit";
import { IssueActivity } from "../issue-activity";
import { getRepo, parseGitHubUrl } from "../start";
import { EnvConfig } from "../types/env-type";
import { BaseModule } from "../types/module";
import { Result } from "../types/results";
import { isAdmin, isCollaborative } from "../helpers/checkers";

interface Payload {
evmNetworkId: number;
Expand Down Expand Up @@ -110,28 +109,23 @@ export class PermitGenerationModule extends BaseModule {
},
],
};
const permits = await generatePayoutPermit(
{
result[key].permitUrl = `https://pay.ubq.fi?claim=${await generatePermitUrlPayload(
this.context,
key,
payload.evmNetworkId,
value.total,
payload.erc20RewardToken,
createAdapters(this._supabase, {
env,
eventName,
logger: permitLogger,
payload,
adapters: createAdapters(this._supabase, {
env,
eventName,
octokit,
config,
logger: permitLogger,
payload,
adapters,
}),
octokit,
config,
},
config.permitRequests
);
result[key].permitUrl = `https://pay.ubq.fi?claim=${encodePermits(permits)}`;
await this._savePermitsToDatabase(result[key].userId, { issueUrl: payload.issueUrl, issueId }, permits);
logger: permitLogger,
payload,
adapters,
})
)}`;
// await this._savePermitsToDatabase(result[key].userId, { issueUrl: payload.issueUrl, issueId }, permits);
} catch (e) {
this.context.logger.error(`[PermitGenerationModule] Failed to generate permits for user ${key}`, { e });
}
Expand Down

0 comments on commit d6bb847

Please sign in to comment.