From 6c9f5c7e394c7c5ff93c49359077b8eb130eadb4 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 13 Dec 2024 11:49:46 -0500 Subject: [PATCH] sdk: add PaladinVerifier type Signed-off-by: Andrew Richardson --- sdk/typescript/src/domains/noto.ts | 54 +++++++++------ sdk/typescript/src/domains/pente.ts | 65 ++++++++++++++----- sdk/typescript/src/domains/zeto.ts | 23 ++++--- sdk/typescript/src/index.ts | 1 + .../src/interfaces/domains/pente.ts | 7 ++ sdk/typescript/src/interfaces/transaction.ts | 39 ----------- sdk/typescript/src/paladin.ts | 5 ++ sdk/typescript/src/verifier.ts | 18 +++++ 8 files changed, 129 insertions(+), 83 deletions(-) create mode 100644 sdk/typescript/src/verifier.ts diff --git a/sdk/typescript/src/domains/noto.ts b/sdk/typescript/src/domains/noto.ts index e7df0e8b9..351eb53e0 100644 --- a/sdk/typescript/src/domains/noto.ts +++ b/sdk/typescript/src/domains/noto.ts @@ -3,6 +3,7 @@ import { IGroupInfo, IStateEncoded, TransactionType } from "../interfaces"; import PaladinClient from "../paladin"; import * as notoPrivateJSON from "./abis/INotoPrivate.json"; import { penteGroupABI } from "./pente"; +import { PaladinVerifier } from "../verifier"; const DEFAULT_POLL_TIMEOUT = 10000; @@ -38,7 +39,7 @@ export const notoConstructorABI = ( }); export interface NotoConstructorParams { - notary: string; + notary: PaladinVerifier; hooks?: { privateGroup?: IGroupInfo; publicAddress?: string; @@ -48,13 +49,13 @@ export interface NotoConstructorParams { } export interface NotoMintParams { - to: string; + to: PaladinVerifier; amount: string | number; data: string; } export interface NotoTransferParams { - to: string; + to: PaladinVerifier; amount: string | number; data: string; } @@ -89,14 +90,17 @@ export class NotoFactory { return new NotoFactory(paladin, this.domain, this.options); } - async newNoto(from: string, data: NotoConstructorParams) { + async newNoto(from: PaladinVerifier, data: NotoConstructorParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, domain: this.domain, abi: [notoConstructorABI(!!data.hooks)], function: "", - from, - data, + from: from.lookup, + data: { + ...data, + notary: data.notary.lookup, + }, }); const receipt = await this.paladin.pollForReceipt( txID, @@ -126,38 +130,47 @@ export class NotoInstance { return new NotoInstance(paladin, this.address, this.options); } - async mint(from: string, data: NotoMintParams) { + async mint(from: PaladinVerifier, data: NotoMintParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, abi: notoPrivateJSON.abi, function: "mint", to: this.address, - from, - data, + from: from.lookup, + data: { + ...data, + to: data.to.lookup, + }, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); } - async transfer(from: string, data: NotoTransferParams) { + async transfer(from: PaladinVerifier, data: NotoTransferParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, abi: notoPrivateJSON.abi, function: "transfer", to: this.address, - from, - data, + from: from.lookup, + data: { + ...data, + to: data.to.lookup, + }, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); } - async prepareTransfer(from: string, data: NotoTransferParams) { + async prepareTransfer(from: PaladinVerifier, data: NotoTransferParams) { const txID = await this.paladin.prepareTransaction({ type: TransactionType.PRIVATE, abi: notoPrivateJSON.abi, function: "transfer", to: this.address, - from, - data, + from: from.lookup, + data: { + ...data, + to: data.to.lookup, + }, }); return this.paladin.pollForPreparedTransaction( txID, @@ -165,25 +178,28 @@ export class NotoInstance { ); } - async approveTransfer(from: string, data: NotoApproveTransferParams) { + async approveTransfer( + from: PaladinVerifier, + data: NotoApproveTransferParams + ) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, abi: notoPrivateJSON.abi, function: "approveTransfer", to: this.address, - from, + from: from.lookup, data, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); } - async burn(from: string, data: NotoBurnParams) { + async burn(from: PaladinVerifier, data: NotoBurnParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, abi: notoPrivateJSON.abi, function: "burn", to: this.address, - from, + from: from.lookup, data, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); diff --git a/sdk/typescript/src/domains/pente.ts b/sdk/typescript/src/domains/pente.ts index 1563874a7..e3011b385 100644 --- a/sdk/typescript/src/domains/pente.ts +++ b/sdk/typescript/src/domains/pente.ts @@ -1,8 +1,13 @@ import { randomBytes } from "crypto"; import { ethers } from "ethers"; -import { IGroupInfo, TransactionType } from "../interfaces"; +import { + IGroupInfo, + IGroupInfoUnresolved, + TransactionType, +} from "../interfaces"; import PaladinClient from "../paladin"; import * as penteJSON from "./abis/PentePrivacyGroup.json"; +import { PaladinVerifier } from "../verifier"; const DEFAULT_POLL_TIMEOUT = 10000; @@ -70,7 +75,7 @@ const privateCallABI = ( }); export interface PentePrivacyGroupParams { - group: IGroupInfo; + group: IGroupInfo | IGroupInfoUnresolved; evmVersion: string; endorsementType: string; externalCallsEnabled: boolean; @@ -86,6 +91,20 @@ export interface PenteApproveTransitionParams { export const newGroupSalt = () => "0x" + Buffer.from(randomBytes(32)).toString("hex"); +export const resolveGroup = ( + group: IGroupInfo | IGroupInfoUnresolved +): IGroupInfo => { + const members: string[] = []; + for (const member of group.members) { + if (typeof member === "string") { + members.push(member); + } else { + members.push(member.lookup); + } + } + return { members, salt: group.salt }; +}; + export class PenteFactory { private options: Required; @@ -104,14 +123,17 @@ export class PenteFactory { return new PenteFactory(paladin, this.domain, this.options); } - async newPrivacyGroup(from: string, data: PentePrivacyGroupParams) { + async newPrivacyGroup(from: PaladinVerifier, data: PentePrivacyGroupParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, domain: this.domain, abi: [penteConstructorABI], function: "", - from, - data, + from: from.lookup, + data: { + ...data, + group: resolveGroup(data.group), + }, }); const receipt = await this.paladin.pollForReceipt( txID, @@ -121,7 +143,7 @@ export class PenteFactory { ? undefined : new PentePrivacyGroup( this.paladin, - data.group, + resolveGroup(data.group), receipt.contractAddress, this.options ); @@ -155,7 +177,7 @@ export class PentePrivacyGroup { async deploy( abi: ReadonlyArray, bytecode: string, - from: string, + from: PaladinVerifier, inputs: ConstructorParams ) { const constructor = abi.find((entry) => entry.type === "constructor"); @@ -167,7 +189,7 @@ export class PentePrivacyGroup { abi: [privateDeployABI(constructor.inputs ?? [])], function: "deploy", to: this.address, - from, + from: from.lookup, data: { group: this.group, bytecode, inputs }, }); const receipt = await this.paladin.pollForReceipt( @@ -179,7 +201,7 @@ export class PentePrivacyGroup { } async invoke( - from: string, + from: PaladinVerifier, to: string, methodAbi: ethers.JsonFragment, inputs: Params @@ -189,14 +211,14 @@ export class PentePrivacyGroup { abi: [privateInvokeABI(methodAbi.name ?? "", methodAbi.inputs ?? [])], function: "", to: this.address, - from, + from: from.lookup, data: { group: this.group, to, inputs }, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); } async call( - from: string, + from: PaladinVerifier, to: string, methodAbi: ethers.JsonFragment, inputs: Params @@ -212,18 +234,21 @@ export class PentePrivacyGroup { ], function: "", to: this.address, - from, + from: from.lookup, data: { group: this.group, to, inputs }, }); } - async approveTransition(from: string, data: PenteApproveTransitionParams) { + async approveTransition( + from: PaladinVerifier, + data: PenteApproveTransitionParams + ) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PUBLIC, abi: penteJSON.abi, function: "approveTransition", to: this.address, - from, + from: from.lookup, data, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); @@ -241,7 +266,11 @@ export abstract class PentePrivateContract { paladin: PaladinClient ): PentePrivateContract; - async invoke(from: string, methodName: string, params: Params) { + async invoke( + from: PaladinVerifier, + methodName: string, + params: Params + ) { const method = this.abi.find((entry) => entry.name === methodName); if (method === undefined) { throw new Error(`Method '${methodName}' not found`); @@ -249,7 +278,11 @@ export abstract class PentePrivateContract { return this.evm.invoke(from, this.address, method, params); } - async call(from: string, methodName: string, params: Params) { + async call( + from: PaladinVerifier, + methodName: string, + params: Params + ) { const method = this.abi.find((entry) => entry.name === methodName); if (method === undefined) { throw new Error(`Method '${methodName}' not found`); diff --git a/sdk/typescript/src/domains/zeto.ts b/sdk/typescript/src/domains/zeto.ts index 2aedc9b64..c85bc16b0 100644 --- a/sdk/typescript/src/domains/zeto.ts +++ b/sdk/typescript/src/domains/zeto.ts @@ -1,5 +1,6 @@ import { TransactionType } from "../interfaces"; import PaladinClient from "../paladin"; +import { PaladinVerifier } from "../verifier"; const DEFAULT_POLL_TIMEOUT = 10000; @@ -74,7 +75,7 @@ export interface ZetoTransferParams { } export interface ZetoTransfer { - to: string; + to: PaladinVerifier; amount: string | number; } @@ -96,13 +97,13 @@ export class ZetoFactory { return new ZetoFactory(paladin, this.domain, this.options); } - async newZeto(from: string, data: ZetoConstructorParams) { + async newZeto(from: PaladinVerifier, data: ZetoConstructorParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, domain: this.domain, abi: [zetoConstructorABI], function: "", - from, + from: from.lookup, data, }); const receipt = await this.paladin.pollForReceipt( @@ -133,26 +134,30 @@ export class ZetoInstance { return new ZetoInstance(paladin, this.address, this.options); } - async mint(from: string, data: ZetoMintParams) { + async mint(from: PaladinVerifier, data: ZetoMintParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, abi: zetoPrivateAbi, function: "mint", to: this.address, - from, - data, + from: from.lookup, + data: { + mints: data.mints.map((t) => ({ ...t, to: t.to.lookup })), + }, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); } - async transfer(from: string, data: ZetoTransferParams) { + async transfer(from: PaladinVerifier, data: ZetoTransferParams) { const txID = await this.paladin.sendTransaction({ type: TransactionType.PRIVATE, abi: zetoPrivateAbi, function: "transfer", to: this.address, - from, - data, + from: from.lookup, + data: { + transfers: data.transfers.map((t) => ({ ...t, to: t.to.lookup })), + }, }); return this.paladin.pollForReceipt(txID, this.options.pollTimeout); } diff --git a/sdk/typescript/src/index.ts b/sdk/typescript/src/index.ts index f24231406..36891bc47 100644 --- a/sdk/typescript/src/index.ts +++ b/sdk/typescript/src/index.ts @@ -3,6 +3,7 @@ export default PaladinClient; export * from "./interfaces/index"; export * from "./utils"; +export * from "./verifier"; export * from "./domains/noto"; export * from "./domains/pente"; export * from "./domains/zeto"; diff --git a/sdk/typescript/src/interfaces/domains/pente.ts b/sdk/typescript/src/interfaces/domains/pente.ts index f37fa7394..50b65480b 100644 --- a/sdk/typescript/src/interfaces/domains/pente.ts +++ b/sdk/typescript/src/interfaces/domains/pente.ts @@ -1,4 +1,11 @@ +import { PaladinVerifier } from "../../verifier"; + export interface IGroupInfo { salt: string; members: string[]; } + +export interface IGroupInfoUnresolved { + salt: string; + members: PaladinVerifier[]; +} diff --git a/sdk/typescript/src/interfaces/transaction.ts b/sdk/typescript/src/interfaces/transaction.ts index 9859117cb..e8c78a9f9 100644 --- a/sdk/typescript/src/interfaces/transaction.ts +++ b/sdk/typescript/src/interfaces/transaction.ts @@ -94,45 +94,6 @@ export interface ITransactionStates { }; } -export interface ITransactionDependencies { - dependsOn: string[]; - prereqOf: string[]; -} - -export interface IPublicTxWithBinding { - to?: string; - data?: string; - from: string; - nonce: string; - created: string; - completedAt?: string; - transactionHash?: string; - success?: boolean; - revertData?: string; - submissions?: IPublicTxSubmissionData[]; - activity?: ITransactionActivityRecord[]; - gas?: string; - value?: string; - maxPriorityFeePerGas?: string; - maxFeePerGas?: string; - gasPrice?: string; - transaction: string; - transactionType: TransactionType; -} - -export interface IPublicTxSubmissionData { - time: string; - transactionHash: string; - maxPriorityFeePerGas?: string; - maxFeePerGas?: string; - gasPrice?: string; -} - -export interface ITransactionActivityRecord { - time: string; - message: string; -} - export enum TransactionType { Private = "private", Public = "public", diff --git a/sdk/typescript/src/paladin.ts b/sdk/typescript/src/paladin.ts index 30abc60eb..75b2d869f 100644 --- a/sdk/typescript/src/paladin.ts +++ b/sdk/typescript/src/paladin.ts @@ -17,6 +17,7 @@ import { } from "./interfaces/transaction"; import { Algorithms, Verifiers } from "./interfaces"; import { ethers } from "ethers"; +import { PaladinVerifier } from "./verifier"; const POLL_INTERVAL_MS = 100; @@ -55,6 +56,10 @@ export default class PaladinClient { }; } + getVerifiers(...lookups: string[]) { + return lookups.map((lookup) => new PaladinVerifier(this, lookup)); + } + parseAxiosErrorMessage(err: any) { if (err instanceof AxiosError && err.response?.data?.error) { return err.response.data.error?.message || err.response.data.error; diff --git a/sdk/typescript/src/verifier.ts b/sdk/typescript/src/verifier.ts new file mode 100644 index 000000000..93b636a3a --- /dev/null +++ b/sdk/typescript/src/verifier.ts @@ -0,0 +1,18 @@ +import { Algorithms, JsonRpcResult, Verifiers } from "./interfaces"; +import PaladinClient from "./paladin"; + +export class PaladinVerifier { + constructor(private paladin: PaladinClient, public readonly lookup: string) {} + + toString() { + return this.lookup; + } + + resolve(algorithm: Algorithms, verifierType: Verifiers) { + return this.paladin.resolveVerifier(this.lookup, algorithm, verifierType); + } + + address() { + return this.resolve(Algorithms.ECDSA_SECP256K1, Verifiers.ETH_ADDRESS); + } +}