mirror of
https://github.com/AtHeartEngineering/bandada.git
synced 2026-01-09 20:28:06 -05:00
refactor(utils): merge contract-utils and utils libraries
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "@zk-groups/contract-utils",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"ethers": "^6.0.5"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import ZKGroups from "contract-artifacts/ZKGroups.json"
|
||||
import Semaphore from "contract-artifacts/Semaphore.json"
|
||||
import { Contract } from "ethers"
|
||||
import { getNetworkConfig } from "./networks"
|
||||
import { ContractName } from "./types"
|
||||
|
||||
export default function getContractInstance(
|
||||
contractName: ContractName
|
||||
): Contract {
|
||||
const network = getNetworkConfig()
|
||||
|
||||
switch (contractName) {
|
||||
case "ZKGroups":
|
||||
return new Contract(network.zkGroupsContract, ZKGroups.abi)
|
||||
case "Semaphore":
|
||||
return new Contract(network.semaphoreContract, Semaphore.abi)
|
||||
default:
|
||||
throw new TypeError(`'${contractName}' contract does not exist`)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import { JsonRpcProvider } from "ethers"
|
||||
import { getNetworkConfig } from "./networks"
|
||||
import { Network } from "./types"
|
||||
|
||||
export default function getProvider(networkName: Network): JsonRpcProvider {
|
||||
const network = getNetworkConfig(networkName)
|
||||
const provider = new JsonRpcProvider(network.url)
|
||||
return provider
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import { Signer, Wallet } from "ethers"
|
||||
import getProvider from "./getProvider"
|
||||
import { Network } from "./types"
|
||||
|
||||
export default async function getSigner(networkName: Network): Promise<Signer> {
|
||||
if (!process.env["BACKEND_PRIVATE_KEY"]) {
|
||||
throw new Error("Please set your BACKEND_PRIVATE_KEY in your .env file")
|
||||
}
|
||||
|
||||
const provider = getProvider(networkName)
|
||||
|
||||
// TODO: move ethers from an Hardhat account to the backend account.
|
||||
return new Wallet(process.env["BACKEND_PRIVATE_KEY"], provider)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import * as zkGroups from "./zkGroups"
|
||||
import * as semaphore from "./semaphore"
|
||||
import NETWORKS from "./networks"
|
||||
import getSigner from "./getSigner"
|
||||
import getProvider from "./getProvider"
|
||||
import getContractInstance from "./getContractInstance"
|
||||
|
||||
export {
|
||||
getSigner,
|
||||
getProvider,
|
||||
getContractInstance,
|
||||
semaphore,
|
||||
zkGroups,
|
||||
NETWORKS
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { Network } from "./types"
|
||||
|
||||
type NetworkConfigParams = {
|
||||
url: string
|
||||
chainId: number
|
||||
semaphoreContract: string
|
||||
zkGroupsContract: string
|
||||
}
|
||||
|
||||
const infuraApiKey = process.env.INFURA_API_KEY
|
||||
|
||||
const NETWORKS: { [K in Network]?: NetworkConfigParams } = {
|
||||
localhost: {
|
||||
url: "http://127.0.0.1:8545",
|
||||
chainId: 31337,
|
||||
semaphoreContract: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
|
||||
zkGroupsContract: "0x5FbDB2315678afecb367f032d93F642f64180aa3"
|
||||
},
|
||||
goerli: {
|
||||
url: `https://goerli.infura.io/v3/${infuraApiKey}`,
|
||||
chainId: 5,
|
||||
semaphoreContract: "0x89490c95eD199D980Cdb4FF8Bac9977EDb41A7E7",
|
||||
zkGroupsContract: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
|
||||
},
|
||||
arbitrum: {
|
||||
url: "https://arb1.arbitrum.io/rpc",
|
||||
chainId: 42161,
|
||||
semaphoreContract: "",
|
||||
zkGroupsContract: ""
|
||||
}
|
||||
}
|
||||
|
||||
export function getNetworkConfig(
|
||||
networkName = process.env.NX_DEFAULT_NETWORK as Network
|
||||
) {
|
||||
if (networkName !== "localhost" && !process.env["INFURA_API_KEY"]) {
|
||||
throw new Error("Please set your INFURA_API_KEY in your .env file")
|
||||
}
|
||||
|
||||
const network = NETWORKS[networkName]
|
||||
if (!network) {
|
||||
throw new Error(
|
||||
"'networkName' not provided or invalid value set for 'NX_DEFAULT_NETWORK' env variable"
|
||||
)
|
||||
}
|
||||
|
||||
return network
|
||||
}
|
||||
|
||||
export default NETWORKS
|
||||
@@ -1,74 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import { Signer, TransactionReceipt } from "ethers"
|
||||
import { formatBytes32String } from "ethers/lib/utils"
|
||||
import getContractInstance from "./getContractInstance"
|
||||
|
||||
export function formatUint256String(text: string): BigInt {
|
||||
return BigInt(formatBytes32String(text))
|
||||
}
|
||||
|
||||
export async function createGroup(
|
||||
signer: Signer,
|
||||
groupName: string,
|
||||
merkleTreeDepth: number
|
||||
): Promise<any> {
|
||||
const admin = signer
|
||||
const groupId = formatUint256String(groupName)
|
||||
const contractInstance = getContractInstance("Semaphore").connect(admin)
|
||||
|
||||
const transaction = await contractInstance[
|
||||
"createGroup(uint256,uint256,address)"
|
||||
](groupId, merkleTreeDepth, await admin.getAddress())
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
|
||||
export async function updateGroupAdmin(
|
||||
signer: Signer,
|
||||
groupName: string,
|
||||
newAdmin: string
|
||||
): Promise<TransactionReceipt> {
|
||||
const admin = signer
|
||||
const groupId = formatUint256String(groupName)
|
||||
const contractInstance = getContractInstance("Semaphore").connect(admin)
|
||||
|
||||
const transaction = await contractInstance[
|
||||
"updateGroupAdmin(uint256,address)"
|
||||
](groupId, newAdmin)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
|
||||
export async function addMember(
|
||||
signer: Signer,
|
||||
groupName: string,
|
||||
member: string
|
||||
): Promise<TransactionReceipt> {
|
||||
const admin = signer
|
||||
const groupId = formatUint256String(groupName)
|
||||
const contractInstance = getContractInstance("Semaphore").connect(admin)
|
||||
|
||||
const transaction = await contractInstance["addMember(uint256,uint256)"](
|
||||
groupId,
|
||||
member
|
||||
)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
|
||||
export async function addMembers(
|
||||
signer: Signer,
|
||||
groupName: string,
|
||||
members: string[]
|
||||
): Promise<TransactionReceipt> {
|
||||
const admin = signer
|
||||
const groupId = formatUint256String(groupName)
|
||||
const contractInstance = getContractInstance("Semaphore").connect(admin)
|
||||
|
||||
const transaction = await contractInstance["addMembers(uint256,uint256[])"](
|
||||
groupId,
|
||||
members
|
||||
)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Supported networks: https://docs.ethers.org/v5/api/providers/api-providers/#InfuraProvider
|
||||
export type Network =
|
||||
| "homestead"
|
||||
| "goerli"
|
||||
| "sepolia"
|
||||
| "arbitrum"
|
||||
| "matic"
|
||||
| "optimism"
|
||||
| "localhost"
|
||||
|
||||
export type ContractName = "ZKGroups" | "Semaphore"
|
||||
@@ -1,24 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import { TransactionReceipt } from "ethers"
|
||||
import getContractInstance from "./getContractInstance"
|
||||
import getSigner from "./getSigner"
|
||||
import { Network } from "./types"
|
||||
|
||||
export type Group = {
|
||||
id: BigInt
|
||||
fingerprint: BigInt
|
||||
}
|
||||
|
||||
export async function updateGroups(
|
||||
groups: Group[],
|
||||
network: Network = process.env.NX_DEFAULT_NETWORK as Network
|
||||
): Promise<TransactionReceipt> {
|
||||
const signer = await getSigner(network)
|
||||
const contractInstance = getContractInstance("ZKGroups").connect(
|
||||
signer
|
||||
) as any
|
||||
|
||||
const transaction = await contractInstance.updateGroups(groups)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -29,6 +29,7 @@
|
||||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"rimraf": "^4.1.2",
|
||||
"rollup": "^3.17.2",
|
||||
@@ -37,6 +38,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ethersproject/address": "^5.7.0",
|
||||
"@ethersproject/contracts": "^5.7.0",
|
||||
"@ethersproject/providers": "^5.7.0",
|
||||
"@ethersproject/strings": "^5.7.0",
|
||||
"@ethersproject/wallet": "^5.7.0",
|
||||
"axios": "^1.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import typescript from "@rollup/plugin-typescript"
|
||||
import json from "@rollup/plugin-json"
|
||||
import * as fs from "fs"
|
||||
import cleanup from "rollup-plugin-cleanup"
|
||||
|
||||
@@ -20,6 +21,7 @@ export default {
|
||||
],
|
||||
external: Object.keys(pkg.dependencies),
|
||||
plugins: [
|
||||
json(),
|
||||
typescript({
|
||||
tsconfig: "./tsconfig.build.json"
|
||||
}),
|
||||
|
||||
21
libs/utils/src/contract-addresses.ts
Normal file
21
libs/utils/src/contract-addresses.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ContractName, Network } from "./types"
|
||||
|
||||
const CONTRACT_ADDRESSES: { [K in Network]: { [Y in ContractName]: string } } =
|
||||
{
|
||||
localhost: {
|
||||
Semaphore: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
|
||||
ZKGroups: "0x5FbDB2315678afecb367f032d93F642f64180aa3"
|
||||
},
|
||||
goerli: {
|
||||
Semaphore: "0x89490c95eD199D980Cdb4FF8Bac9977EDb41A7E7",
|
||||
ZKGroups: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
|
||||
}
|
||||
}
|
||||
|
||||
export function getContractAddresses(networkName: Network): {
|
||||
[Y in ContractName]: string
|
||||
} {
|
||||
return CONTRACT_ADDRESSES[networkName]
|
||||
}
|
||||
|
||||
export default CONTRACT_ADDRESSES
|
||||
28
libs/utils/src/getContract.ts
Normal file
28
libs/utils/src/getContract.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Contract } from "@ethersproject/contracts"
|
||||
import { getContractAddresses } from "./contract-addresses"
|
||||
import { abi as SemaphoreABI } from "./contract-artifacts/Semaphore.json"
|
||||
import { abi as ZKGroupsABI } from "./contract-artifacts/ZKGroups.json"
|
||||
import getProvider from "./getProvider"
|
||||
import getWallet from "./getWallet"
|
||||
import { ContractName, Network } from "./types"
|
||||
|
||||
export default function getContract(
|
||||
contractName: ContractName,
|
||||
network: Network,
|
||||
privateKey?: string
|
||||
): Contract {
|
||||
const providerOrWallet = privateKey
|
||||
? getWallet(privateKey, network)
|
||||
: getProvider(network)
|
||||
|
||||
const contractAddress = getContractAddresses(network)[contractName]
|
||||
|
||||
switch (contractName) {
|
||||
case "ZKGroups":
|
||||
return new Contract(contractAddress, ZKGroupsABI, providerOrWallet)
|
||||
case "Semaphore":
|
||||
return new Contract(contractAddress, SemaphoreABI, providerOrWallet)
|
||||
default:
|
||||
throw new TypeError(`'${contractName}' contract does not exist`)
|
||||
}
|
||||
}
|
||||
16
libs/utils/src/getProvider.ts
Normal file
16
libs/utils/src/getProvider.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { InfuraProvider, JsonRpcProvider } from "@ethersproject/providers"
|
||||
import { Network } from "./types"
|
||||
|
||||
export default function getProvider(
|
||||
network: Network,
|
||||
apiKey?: string
|
||||
): JsonRpcProvider {
|
||||
switch (network) {
|
||||
case "localhost":
|
||||
return new JsonRpcProvider()
|
||||
case "goerli":
|
||||
return new InfuraProvider(network, apiKey)
|
||||
default:
|
||||
throw new TypeError(`'${network}' network is not supported`)
|
||||
}
|
||||
}
|
||||
73
libs/utils/src/getSemaphoreContract.ts
Normal file
73
libs/utils/src/getSemaphoreContract.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Contract, ContractReceipt } from "@ethersproject/contracts"
|
||||
import { formatBytes32String } from "@ethersproject/strings"
|
||||
import getContract from "./getContract"
|
||||
import { Network } from "./types"
|
||||
|
||||
export class SemaphoreContract {
|
||||
private contract: Contract
|
||||
|
||||
constructor(contract: Contract) {
|
||||
this.contract = contract
|
||||
}
|
||||
|
||||
async createGroup(
|
||||
groupName: string,
|
||||
merkleTreeDepth: number,
|
||||
admin: string
|
||||
): Promise<ContractReceipt> {
|
||||
const groupId = BigInt(formatBytes32String(groupName))
|
||||
|
||||
const transaction = await this.contract.createGroup(
|
||||
groupId,
|
||||
merkleTreeDepth,
|
||||
admin
|
||||
)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
|
||||
async updateGroupAdmin(
|
||||
groupName: string,
|
||||
newAdmin: string
|
||||
): Promise<ContractReceipt> {
|
||||
const groupId = BigInt(formatBytes32String(groupName))
|
||||
|
||||
const transaction = await this.contract.updateGroupAdmin(
|
||||
groupId,
|
||||
newAdmin
|
||||
)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
|
||||
async addMember(
|
||||
groupName: string,
|
||||
member: string
|
||||
): Promise<ContractReceipt> {
|
||||
const groupId = BigInt(formatBytes32String(groupName))
|
||||
|
||||
const transaction = await this.contract.addMember(groupId, member)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
|
||||
async addMembers(
|
||||
groupName: string,
|
||||
members: string[]
|
||||
): Promise<ContractReceipt> {
|
||||
const groupId = BigInt(formatBytes32String(groupName))
|
||||
|
||||
const transaction = await this.contract.addMembers(groupId, members)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
}
|
||||
|
||||
export default function getSemaphoreContract(
|
||||
network: Network,
|
||||
privateKey: string
|
||||
): SemaphoreContract {
|
||||
const contract = getContract("Semaphore", network, privateKey)
|
||||
|
||||
return new SemaphoreContract(contract)
|
||||
}
|
||||
16
libs/utils/src/getWallet.ts
Normal file
16
libs/utils/src/getWallet.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Wallet } from "@ethersproject/wallet"
|
||||
import getProvider from "./getProvider"
|
||||
import { Network } from "./types"
|
||||
|
||||
export default function getWallet(
|
||||
privateKey: string,
|
||||
network?: Network
|
||||
): Wallet {
|
||||
if (network) {
|
||||
const provider = getProvider(network)
|
||||
|
||||
return new Wallet(privateKey, provider)
|
||||
}
|
||||
|
||||
return new Wallet(privateKey)
|
||||
}
|
||||
26
libs/utils/src/getZKGroupsContract.ts
Normal file
26
libs/utils/src/getZKGroupsContract.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Contract, ContractReceipt } from "@ethersproject/contracts"
|
||||
import getContract from "./getContract"
|
||||
import { Network, OnchainZKGroup } from "./types"
|
||||
|
||||
export class ZKGroupsContract {
|
||||
private contract: Contract
|
||||
|
||||
constructor(contract: Contract) {
|
||||
this.contract = contract
|
||||
}
|
||||
|
||||
async updateGroups(groups: OnchainZKGroup[]): Promise<ContractReceipt> {
|
||||
const transaction = await this.contract.updateGroups(groups)
|
||||
|
||||
return transaction.wait(1)
|
||||
}
|
||||
}
|
||||
|
||||
export default function getZKGroupsContract(
|
||||
network: Network,
|
||||
privateKey: string
|
||||
): ZKGroupsContract {
|
||||
const contract = getContract("ZKGroups", network, privateKey)
|
||||
|
||||
return new ZKGroupsContract(contract)
|
||||
}
|
||||
13
libs/utils/src/index.test.ts
Normal file
13
libs/utils/src/index.test.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import shortenAddress from "./shortenAddress"
|
||||
|
||||
describe("Utils", () => {
|
||||
describe("# shortenAddress", () => {
|
||||
it("Should shorten an Ethereum address", () => {
|
||||
const address = shortenAddress(
|
||||
"0x1234567890123456789012345678901234567890"
|
||||
)
|
||||
|
||||
expect(address).toBe("0x1234...7890")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,27 @@
|
||||
import CONTRACT_ADDRESSES, { getContractAddresses } from "./contract-addresses"
|
||||
import { abi as SemaphoreABI } from "./contract-artifacts/Semaphore.json"
|
||||
import { abi as ZKGroupsABI } from "./contract-artifacts/ZKGroups.json"
|
||||
import getContract from "./getContract"
|
||||
import getProvider from "./getProvider"
|
||||
import getSemaphoreContract, { SemaphoreContract } from "./getSemaphoreContract"
|
||||
import getWallet from "./getWallet"
|
||||
import getZKGroupsContract, { ZKGroupsContract } from "./getZKGroupsContract"
|
||||
import request from "./request"
|
||||
import shortenAddress from "./shortenAddress"
|
||||
|
||||
export { request, shortenAddress }
|
||||
export * from "./types/index"
|
||||
export {
|
||||
request,
|
||||
shortenAddress,
|
||||
getProvider,
|
||||
getContract,
|
||||
getSemaphoreContract,
|
||||
SemaphoreContract,
|
||||
getZKGroupsContract,
|
||||
ZKGroupsContract,
|
||||
getWallet,
|
||||
CONTRACT_ADDRESSES,
|
||||
getContractAddresses,
|
||||
SemaphoreABI,
|
||||
ZKGroupsABI
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import axios, { AxiosRequestConfig, AxiosResponse } from "axios"
|
||||
|
||||
/* istanbul ignore next */
|
||||
export default async function request(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig
|
||||
|
||||
19
libs/utils/src/types/index.ts
Normal file
19
libs/utils/src/types/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// Supported networks: https://docs.ethers.org/v5/api/providers/api-providers/#InfuraProvider
|
||||
export type Network =
|
||||
| "localhost"
|
||||
// | "homestead"
|
||||
| "goerli"
|
||||
// | "sepolia"
|
||||
// | "arbitrum"
|
||||
// | "arbitrum-goerli"
|
||||
// | "matic"
|
||||
// | "maticmum"
|
||||
// | "optimism"
|
||||
// | "optimism-goerli"
|
||||
|
||||
export type ContractName = "ZKGroups" | "Semaphore"
|
||||
|
||||
export type OnchainZKGroup = {
|
||||
id: BigInt
|
||||
fingerprint: BigInt
|
||||
}
|
||||
Reference in New Issue
Block a user