Skip to content

Commit

Permalink
Merge pull request #7 from gentlementlegen/feat/npm-package
Browse files Browse the repository at this point in the history
feat: npm package
  • Loading branch information
whilefoo authored Apr 9, 2024
2 parents 9901499 + 1585826 commit a54158a
Show file tree
Hide file tree
Showing 20 changed files with 741 additions and 215 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/jest-testing.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Run Jest testing suite
on:
workflow_dispatch:
pull_request_target:
pull_request:
types: [opened, synchronize]

env:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/publish-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish Package

on:
workflow_dispatch:
push:
branches:
- main

jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
with:
release-type: node
package-name: "@ubiquibot/permit-generation"
default-branch: main
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.10.0'
registry-url: https://registry.npmjs.org/
- run: |
yarn install --immutable --immutable-cache --check-cache
yarn pack
yarn publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ node_modules
.env
static/dist
/coverage
junit.xml
junit.xml
dist
3 changes: 2 additions & 1 deletion knip.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { KnipConfig } from "knip";

const config: KnipConfig = {
entry: ["build/index.ts"],
entry: ["src/main.ts"],
project: ["src/**/*.ts"],
ignore: [],
ignoreBinaries: ["publish"],
ignoreExportsUsedInFile: true,
ignoreDependencies: ["ts-node"],
jest: {
Expand Down
26 changes: 22 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"name": "@ubiquibot/permit-generation",
"version": "1.0.0",
"description": "Template repository with TypeScript support.",
"main": "src/index.ts",
"description": "ECR20 / ECR721 permit generation for automated payments.",
"author": "Ubiquity DAO",
"license": "MIT",
"engines": {
Expand All @@ -16,7 +15,8 @@
"knip": "knip",
"knip-ci": "knip --no-exit-code --reporter json",
"prepare": "husky install",
"test": "jest"
"test": "jest",
"build": "rollup -c"
},
"keywords": [
"typescript",
Expand All @@ -43,6 +43,13 @@
"@cspell/dict-node": "^4.0.3",
"@cspell/dict-software-terms": "^3.3.18",
"@cspell/dict-typescript": "^3.1.2",
"@jest/globals": "29.7.0",
"@jest/types": "29.6.3",
"@rollup/plugin-commonjs": "25.0.7",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-yaml": "4.1.2",
"@types/libsodium-wrappers": "^0.7.8",
"@types/node": "^20.11.19",
"@typescript-eslint/eslint-plugin": "^7.0.1",
Expand All @@ -57,6 +64,9 @@
"lint-staged": "^15.2.2",
"npm-run-all": "^4.1.5",
"prettier": "^3.2.5",
"rollup": "4.14.0",
"rollup-plugin-dts-bundle-generator": "1.4.0",
"rollup-plugin-typescript2": "0.36.0",
"ts-jest": "29.1.2",
"ts-node": "10.9.2",
"tsx": "^4.7.1",
Expand All @@ -75,5 +85,13 @@
"extends": [
"@commitlint/config-conventional"
]
}
},
"files": [
"dist/*",
"README.md",
"package.json"
],
"module": "dist/index.esm.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts"
}
16 changes: 16 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import typescript from "rollup-plugin-typescript2";
import yaml from "@rollup/plugin-yaml";
import { generateDtsBundle } from "rollup-plugin-dts-bundle-generator";
import nodeResolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import terser from "@rollup/plugin-terser";

export default {
input: "src/index.ts",
output: {
dir: "dist",
format: "cjs",
},
plugins: [nodeResolve(), commonjs(), typescript(), yaml(), json(), generateDtsBundle(), terser()],
};
92 changes: 64 additions & 28 deletions src/handlers/generate-erc20-permit.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,77 @@
import { PERMIT2_ADDRESS, PermitTransferFrom, SignatureTransfer } from "@uniswap/permit2-sdk";
import { ethers, keccak256, MaxInt256, parseUnits, toUtf8Bytes } from "ethers";
import { Context } from "../types/context";
import { Context, Logger } from "../types/context";
import { Permit } from "../types/permits";
import { decryptKeys } from "../utils/keys";
import { getPayoutConfigByNetworkId } from "../utils/payoutConfigByNetworkId";

export async function generateErc20PermitSignature(context: Context, username: string, amount: number): Promise<Permit> {
const config = context.config;
const logger = context.logger;
const { evmNetworkId, evmPrivateEncrypted } = config;
const { user, wallet } = context.adapters.supabase;
export async function generateErc20PermitSignature(
username: string,
amount: number,
evmNetworkId: number,
evmPrivateEncrypted: string,
userId: number,
walletAddress: string,
issueId: number,
logger: Logger
): Promise<Permit>;
export async function generateErc20PermitSignature(username: string, amount: number, context: Context): Promise<Permit>;
export async function generateErc20PermitSignature(
username: string,
amount: number,
contextOrNetworkId: Context | number,
evmPrivateEncrypted?: string,
userId?: number,
walletAddress?: string,
issueId?: number,
logger?: Logger
): Promise<Permit> {
let _logger: Logger;
let _userId: number;
let _walletAddress: string;
let _issueId: number;
let _evmNetworkId: number;
let _evmPrivateEncrypted: string;

const userId = await user.getUserIdByUsername(username);
const walletAddress = await wallet.getWalletByUserId(userId);
let issueId: string;
if ("issue" in context.payload) {
issueId = context.payload.issue.id.toString();
} else if ("pull_request" in context.payload) {
issueId = context.payload.pull_request.id.toString();
if (typeof contextOrNetworkId === "number") {
_logger = logger as Logger;
_userId = userId as number;
_walletAddress = walletAddress as string;
_evmNetworkId = contextOrNetworkId;
_evmPrivateEncrypted = evmPrivateEncrypted as string;
_issueId = issueId as number;
} else {
throw new Error("Issue Id is missing");
const config = contextOrNetworkId.config;
_logger = contextOrNetworkId.logger;
const { evmNetworkId, evmPrivateEncrypted } = config;
const { user, wallet } = contextOrNetworkId.adapters.supabase;
_userId = await user.getUserIdByUsername(username);
_walletAddress = await wallet.getWalletByUserId(_userId);
_evmNetworkId = evmNetworkId;
_evmPrivateEncrypted = evmPrivateEncrypted;
if ("issue" in contextOrNetworkId.payload) {
_issueId = contextOrNetworkId.payload.issue.id;
} else if ("pull_request" in contextOrNetworkId.payload) {
_issueId = contextOrNetworkId.payload.pull_request.id;
} else {
throw new Error("Issue Id is missing");
}
}

if (!userId) {
if (!_userId) {
throw new Error("User was not found");
}
if (!walletAddress) {
if (!_walletAddress) {
const errorMessage = "ERC20 Permit generation error: Wallet not found";
logger.error(errorMessage);
_logger.error(errorMessage);
throw new Error(errorMessage);
}

const { rpc, token, decimals } = getPayoutConfigByNetworkId(evmNetworkId);
const { privateKey } = await decryptKeys(evmPrivateEncrypted);
const { rpc, token, decimals } = getPayoutConfigByNetworkId(_evmNetworkId);
const { privateKey } = await decryptKeys(_evmPrivateEncrypted);
if (!privateKey) {
const errorMessage = "Private key is not defined";
logger.fatal(errorMessage);
_logger.fatal(errorMessage);
throw new Error(errorMessage);
}

Expand All @@ -44,26 +80,26 @@ export async function generateErc20PermitSignature(context: Context, username: s
try {
provider = new ethers.JsonRpcProvider(rpc);
} catch (error) {
throw logger.debug("Failed to instantiate provider", error);
throw _logger.debug("Failed to instantiate provider", error);
}

try {
adminWallet = new ethers.Wallet(privateKey, provider);
} catch (error) {
throw logger.debug("Failed to instantiate wallet", error);
throw _logger.debug("Failed to instantiate wallet", error);
}

const permitTransferFromData: PermitTransferFrom = {
permitted: {
token: token,
amount: parseUnits(amount.toString(), decimals),
},
spender: walletAddress,
nonce: BigInt(keccak256(toUtf8Bytes(`${userId}-${issueId}`))),
spender: _walletAddress,
nonce: BigInt(keccak256(toUtf8Bytes(`${_userId}-${_issueId}`))),
deadline: MaxInt256,
};

const { domain, types, values } = SignatureTransfer.getPermitData(permitTransferFromData, PERMIT2_ADDRESS, evmNetworkId);
const { domain, types, values } = SignatureTransfer.getPermitData(permitTransferFromData, PERMIT2_ADDRESS, _evmNetworkId);

const signature = await adminWallet
.signTypedData(
Expand All @@ -79,7 +115,7 @@ export async function generateErc20PermitSignature(context: Context, username: s
)
.catch((error) => {
const errorMessage = `Failed to sign typed data ${error}`;
logger.error(errorMessage);
_logger.error(errorMessage);
throw new Error(errorMessage);
});

Expand All @@ -92,10 +128,10 @@ export async function generateErc20PermitSignature(context: Context, username: s
amount: permitTransferFromData.permitted.amount.toString(),
owner: adminWallet.address,
signature: signature,
networkId: evmNetworkId,
networkId: _evmNetworkId,
};

logger.info("Generated ERC20 permit2 signature", erc20Permit);
_logger.info("Generated ERC20 permit2 signature", erc20Permit);

return erc20Permit;
}
Loading

0 comments on commit a54158a

Please sign in to comment.