From de9f265d8b4198a82509d68de378a3967a30b039 Mon Sep 17 00:00:00 2001 From: "Alex M. (clockwork)" Date: Wed, 18 Oct 2023 18:38:31 -0400 Subject: [PATCH 1/4] feat: Add basic realm module support to GnoWallet --- src/wallet/helpers.ts | 23 +++++++++++++++++++++++ src/wallet/wallet.ts | 17 +++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/wallet/helpers.ts diff --git a/src/wallet/helpers.ts b/src/wallet/helpers.ts new file mode 100644 index 0000000..b0e3b5b --- /dev/null +++ b/src/wallet/helpers.ts @@ -0,0 +1,23 @@ +import { GnoWallet } from "./wallet"; + +export type Constructor = new (...args: any[]) => T; + +export type AnyFunction = (...args: any) => any; + +export type UnionToIntersection = + (Union extends any + ? (argument: Union) => void + : never + ) extends (argument: infer Intersection) => void + ? Intersection + : never; + +export type Return = + T extends AnyFunction + ? ReturnType + : T extends AnyFunction[] + ? UnionToIntersection> + : never + +export type RealmInterface = { [key: string]: any } +export type Realm = (instance: GnoWallet) => { realm: RealmInterface} diff --git a/src/wallet/wallet.ts b/src/wallet/wallet.ts index cbff7c8..463bec1 100644 --- a/src/wallet/wallet.ts +++ b/src/wallet/wallet.ts @@ -11,16 +11,33 @@ import Long from 'long'; import { MemPackage, MsgAddPackage, MsgCall, MsgSend } from '../proto'; import { MsgEndpoint } from './endpoints'; import { LedgerConnector } from '@cosmjs/ledger-amino'; +import { Constructor, Realm, Return, UnionToIntersection } from './helpers'; /** * GnoWallet is an extension of the TM2 wallet with * specific functionality for Gno chains */ export class GnoWallet extends Wallet { + + static realms: Realm[] = []; constructor() { super(); } + static addRealm(realms: T) { + const currentRealms = this.realms; + + class AugmentedWallet extends this { + static realms = currentRealms.concat(realms); + } + if (Array.isArray(realms)) { + type Extension = UnionToIntersection['realm']> + return AugmentedWallet as typeof GnoWallet & Constructor; + } + + type Extension = Return['realm'] + return AugmentedWallet as typeof GnoWallet & Constructor; + } /** * Generates a private key-based wallet, using a random seed * @param {AccountWalletOption} options the account options From 59ec5c3383b9ef1906e2c36f2519dcf1b32642d3 Mon Sep 17 00:00:00 2001 From: "Alex M. (clockwork)" Date: Wed, 18 Oct 2023 18:43:42 -0400 Subject: [PATCH 2/4] feat: Init realm modules in cionstructor --- src/wallet/wallet.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wallet/wallet.ts b/src/wallet/wallet.ts index 463bec1..8d2fc09 100644 --- a/src/wallet/wallet.ts +++ b/src/wallet/wallet.ts @@ -22,6 +22,11 @@ export class GnoWallet extends Wallet { static realms: Realm[] = []; constructor() { super(); + const classConstructor = this.constructor as typeof GnoWallet; + classConstructor.realms.forEach(realm => { + const realmInstance = realm(this); + Object.assign(this, realmInstance.realm); + }); } static addRealm(realms: T) { const currentRealms = this.realms; From d1283ad8ce13f30273c4edef53780fb6c31d07a9 Mon Sep 17 00:00:00 2001 From: "Alex M. (clockwork)" Date: Thu, 19 Oct 2023 17:54:39 -0400 Subject: [PATCH 3/4] feat: Complete example --- src/realm-module-example/realm-module.ts | 66 +++++++++++++++++++++++ src/realm-module-example/usage-example.ts | 8 +++ src/wallet/helpers.ts | 10 ++++ src/wallet/wallet.ts | 11 +++- 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/realm-module-example/realm-module.ts create mode 100644 src/realm-module-example/usage-example.ts diff --git a/src/realm-module-example/realm-module.ts b/src/realm-module-example/realm-module.ts new file mode 100644 index 0000000..74224dc --- /dev/null +++ b/src/realm-module-example/realm-module.ts @@ -0,0 +1,66 @@ +import { BroadcastTransactionMap, TransactionEndpoint, TxFee } from "@gnolang/tm2-js-client"; +import { GnoWallet } from "../wallet"; +import { parseGnoReturns } from "../wallet/helpers"; + +const realm = "/r/demo/boards"; +const realmTS= "r_demo_boards"; +type GetBoardIDFromNameReturn = [number, boolean] +const queryClient = (wallet: GnoWallet) => { + return { + async GetBoardIDFromName(params: { name: string }, height?: number):Promise { + const result = await wallet.getProvider().evaluateExpression(realm,`GetBoardIDFromName("${name}")`,height); + return parseGnoReturns(result) as GetBoardIDFromNameReturn; + } + } +} +const txClient = (wallet: GnoWallet) => { + return { + async GetBoardIDFromName(params: { name: string }, funds: Map, fee: TxFee):Promise { + + const resp = (await wallet.callMethod( + realm, + "GetBoardIDFromName", + [params.name], + TransactionEndpoint.BROADCAST_TX_COMMIT, + funds, + fee + )); + const result = atob(resp.deliver_tx.ResponseBase.Data as string) + return parseGnoReturns(result) as GetBoardIDFromNameReturn; + }, + } +} +class RealmModule { + public query: ReturnType; + public tx: ReturnType; + + constructor(wallet: GnoWallet) { + this.updateQuery(wallet); + this.updateTX(wallet); + } + updateTX(wallet: GnoWallet) { + const methods = txClient(wallet); + + this.tx = methods; + for (let m in methods) { + this.tx[m as keyof typeof methods] = methods[m as keyof typeof methods].bind(this.tx); + } + } + updateQuery(wallet: GnoWallet) { + const methods = queryClient(wallet); + + this.query = methods; + for (let m in methods) { + this.query[m as keyof typeof methods] = methods[m as keyof typeof methods].bind(this.query); + } + } +}; + +const Realm = (wallet: GnoWallet) => { + return { + realm: { + [realmTS]: new RealmModule(wallet) + } + } +} +export default Realm; \ No newline at end of file diff --git a/src/realm-module-example/usage-example.ts b/src/realm-module-example/usage-example.ts new file mode 100644 index 0000000..6e70edc --- /dev/null +++ b/src/realm-module-example/usage-example.ts @@ -0,0 +1,8 @@ +import { GnoWallet } from '../wallet'; +import Realm from './realm-module'; +const RealmWallet = GnoWallet.addRealm(Realm) +const wallet = new RealmWallet(); + +const test = async () => { + const [boardId, exists] = await wallet.r_demo_boards.query.GetBoardIDFromName({ name: "testboard"}); +} \ No newline at end of file diff --git a/src/wallet/helpers.ts b/src/wallet/helpers.ts index b0e3b5b..638911e 100644 --- a/src/wallet/helpers.ts +++ b/src/wallet/helpers.ts @@ -21,3 +21,13 @@ export type Return = export type RealmInterface = { [key: string]: any } export type Realm = (instance: GnoWallet) => { realm: RealmInterface} + +export const parseGnoReturns = (result: string):Array => { + const ret=[]; + const values = result.split("\n"); + for (let i=0; i { + return this.provider; + }; /** * Initiates a native currency transfer transaction between accounts From ac07c7ca11a41434bbe60def425cd6f9bb054e56 Mon Sep 17 00:00:00 2001 From: "Alex M. (clockwork)" Date: Fri, 20 Oct 2023 09:37:30 -0400 Subject: [PATCH 4/4] fix: simplified instantiation --- src/realm-module-example/realm-module.ts | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/realm-module-example/realm-module.ts b/src/realm-module-example/realm-module.ts index 74224dc..a81f284 100644 --- a/src/realm-module-example/realm-module.ts +++ b/src/realm-module-example/realm-module.ts @@ -35,24 +35,8 @@ class RealmModule { public tx: ReturnType; constructor(wallet: GnoWallet) { - this.updateQuery(wallet); - this.updateTX(wallet); - } - updateTX(wallet: GnoWallet) { - const methods = txClient(wallet); - - this.tx = methods; - for (let m in methods) { - this.tx[m as keyof typeof methods] = methods[m as keyof typeof methods].bind(this.tx); - } - } - updateQuery(wallet: GnoWallet) { - const methods = queryClient(wallet); - - this.query = methods; - for (let m in methods) { - this.query[m as keyof typeof methods] = methods[m as keyof typeof methods].bind(this.query); - } + this.tx = txClient(wallet); + this.query = queryClient(wallet); } };