Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactored sdk to use viem #48

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
.secrets
/.idea/*
.DS_Store
src/abis
17 changes: 7 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"scripts": {
"lint:fix": "prettier --write '**/*.ts' && eslint --fix --no-ignore",
"lint": "eslint",
"prebuild": "jq '.type = \"commonjs\"' package.json > temp.json && mv temp.json package.json",
"prebuild": "node scripts/copyAbi.js | jq '.type = \"commonjs\"' package.json > temp.json && mv temp.json package.json",
"build-esm": "tsc --project tsconfig.esm.json",
"build-all": "pnpm run build-commonjs && pnpm run build-esm",
"build-commonjs": "tsc --project tsconfig.commonjs.json",
Expand All @@ -35,33 +35,30 @@
"release": "pnpm build && cd ./dist && changeset publish"
},
"dependencies": {
"@ethersproject/abi": "^5.7.0",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@peeramid-labs/multipass": "^0.3.1",
"@peeramid-labs/multipass": "^0.3.2",
"@peersky/eth-auth": "^2.0.0",
"crypto-js": "^4.1.1",
"ethers": "^5.0.0",
"lodash": "^4.17.21",
"rankify-contracts": "^0.9.3",
"typescript": "^5.0.4",
"@peeramid-labs/eds": "^2.2.0"
"@peeramid-labs/eds": "^2.2.0",
"viem": "^2.21.54"
},
"devDependencies": {
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.2",
"@peersky/eth-auth": "^2.0.0",
"@types/crypto-js": "^4.1.3",
"globals": "^15.9.0",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/eslint-plugin": "^8.17.0",
"@typescript-eslint/parser": "^8.4.0",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.9.1",
"eslint": "^9.9.1",
"eslint-plugin-prettier": "^5.2.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-promise": "^7.1.0",
"eslint-plugin-unused-imports": "^3.0.0",
"eslint-plugin-unused-imports": "^4.1.4",
"prettier": "^3.3.3",
"typescript": "^5.0.4"
"typescript": "^5.7.2"
}
}
448 changes: 280 additions & 168 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions scripts/copyAbi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const fs = require("fs");
const path = require("path");
const { inspect } = require("util");

function processAbiFile(sourcePath, destDir) {
const content = fs.readFileSync(sourcePath, "utf8");
const fileName = path.basename(sourcePath, ".json");
const destPath = path.join(destDir, `${fileName}.ts`);
console.log("parsing abi file", sourcePath);
// Convert JSON to TypeScript
const tsContent = `export const ${fileName}Abi = ${JSON.stringify(JSON.parse(content), null, 2)} as const; export default ${fileName}Abi;`;
fs.writeFileSync(destPath, tsContent);
}

function copyAbiFiles(source, destDir) {
const files = fs.readdirSync(source);

files.forEach((file) => {
const sourcePath = path.join(source, file);

if (fs.lstatSync(sourcePath).isDirectory()) {
copyAbiFiles(sourcePath, destDir);
} else if (file.endsWith(".json")) {
processAbiFile(sourcePath, destDir);
}
});
}

// Ensure src/abis directory exists
const abiDestDir = path.join(__dirname, "../src/abis");
if (!fs.existsSync(abiDestDir)) {
fs.mkdirSync(abiDestDir, { recursive: true });
}

// Copy rankify-contracts ABIs
const rankifyAbiSource = path.join(__dirname, "../node_modules/rankify-contracts/abi");
if (fs.existsSync(rankifyAbiSource)) {
copyAbiFiles(rankifyAbiSource, abiDestDir);
}

// Copy @peeramid-labs ABIs
const peeramidDir = path.join(__dirname, "../node_modules/@peeramid-labs");
if (fs.existsSync(peeramidDir)) {
fs.readdirSync(peeramidDir).forEach((pkg) => {
const abiDir = path.join(peeramidDir, pkg, "abi");
if (fs.existsSync(abiDir)) {
copyAbiFiles(abiDir, abiDestDir);
}
});
}
78 changes: 46 additions & 32 deletions src/eds/Distributor.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,67 @@
import { Distributor } from "@peeramid-labs/eds/types";
import { BigNumberish, Contract, ContractInterface, ethers, Signer } from "ethers";
import { providers } from "ethers";
import { type Address, stringToHex, getContract, Hex, PublicClient } from "viem";
import DistributorAbi from "../abis/Distributor";

export class DistributorClient {
private contract: Distributor;
publicClient: PublicClient;
address: Address;

constructor(address: string, abi: ContractInterface, signerOrProvider: Signer | providers.Provider) {
this.contract = new Contract(address, abi, signerOrProvider) as Distributor;
constructor({ address, publicClient }: { address: Address; publicClient: PublicClient }) {
this.address = address;
this.publicClient = publicClient;
}

// Get the underlying contract instance
public getContract(): Distributor {
return this.contract;
async getDistributions() {
const contract = getContract({
address: this.address,
abi: DistributorAbi,
client: this.publicClient,
});
return contract.read.getDistributions();
}

// Connect with a new signer
public connect(signer: Signer): DistributorClient {
return new DistributorClient(this.contract.address, this.contract.interface, signer);
}
async getInstances(distributorsId: Hex): Promise<Address[][]> {
const contract = getContract({
address: this.address,
abi: DistributorAbi,
client: this.publicClient,
});

getDistributions() {
return this.contract.getDistributions();
}
const events = await contract.getEvents.Instantiated({
distributionId: distributorsId,
});

async getInstances(distributorsId: BigNumberish): Promise<string[][]> {
const filter = this.contract.filters.Instantiated(ethers.utils.hexlify(distributorsId));
const evts = await this.contract.queryFilter(filter);
return evts.map((evt) => evt.args.instances);
return events.map((log) => log.args.instances as Address[]);
}

async getInstance(distributorsId: BigNumberish, instanceId: BigNumberish): Promise<string[]> {
const filter = this.contract.filters.Instantiated(ethers.utils.hexlify(distributorsId), instanceId);
const evts = await this.contract.queryFilter(filter);
const evt = evts[0];
if (evts.length > 1) {
async getInstance(distributorsId: Hex, instanceId: bigint): Promise<Address[]> {
const contract = getContract({
address: this.address,
abi: DistributorAbi,
client: this.publicClient,
});

const events = await contract.getEvents.Instantiated({
distributionId: distributorsId,
newInstanceId: instanceId,
});

if (events.length > 1) {
throw new Error(`Multiple instances found for distributor ${distributorsId} and instance ${instanceId}`);
}
if (evts.length === 0) {
if (events.length === 0) {
throw new Error(`No instances found for distributor ${distributorsId} and instance ${instanceId}`);
}
return evt.args.instances;

return events[0].args.instances as Address[];
}
async getNamedDistributionInstances({ namedDistribution }: { namedDistribution: string }): Promise<string[][]> {
const id = ethers.utils.parseBytes32String(namedDistribution);
return await this.getInstances(id);

async getNamedDistributionInstances({ namedDistribution }: { namedDistribution: string }): Promise<Address[][]> {
const id = stringToHex(namedDistribution, { size: 32 });
return this.getInstances(id);
}

async getNamedDistributionInstance(namedDistribution: string, instanceId: BigNumberish): Promise<string[]> {
const id = ethers.utils.parseBytes32String(namedDistribution);
async getNamedDistributionInstance(namedDistribution: string, instanceId: bigint): Promise<Address[]> {
const id = stringToHex(namedDistribution, { size: 32 });
return this.getInstance(id, instanceId);
}
}
Loading