Skip to content

feat: Add basic realm module support to GnoWallet #57

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
50 changes: 50 additions & 0 deletions src/realm-module-example/realm-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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<GetBoardIDFromNameReturn> {
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<string,number>, fee: TxFee):Promise<GetBoardIDFromNameReturn> {

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<typeof queryClient>;
public tx: ReturnType<typeof txClient>;

constructor(wallet: GnoWallet) {
this.tx = txClient(wallet);
this.query = queryClient(wallet);
}
};

const Realm = (wallet: GnoWallet) => {
return {
realm: {
[realmTS]: new RealmModule(wallet)
}
}
}
export default Realm;
8 changes: 8 additions & 0 deletions src/realm-module-example/usage-example.ts
Original file line number Diff line number Diff line change
@@ -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"});
}
33 changes: 33 additions & 0 deletions src/wallet/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { GnoWallet } from "./wallet";

export type Constructor<T> = new (...args: any[]) => T;

export type AnyFunction = (...args: any) => any;

export type UnionToIntersection<Union> =
(Union extends any
? (argument: Union) => void
: never
) extends (argument: infer Intersection) => void
? Intersection
: never;

export type Return<T> =
T extends AnyFunction
? ReturnType<T>
: T extends AnyFunction[]
? UnionToIntersection<ReturnType<T[number]>>
: never

export type RealmInterface = { [key: string]: any }
export type Realm = (instance: GnoWallet) => { realm: RealmInterface}

export const parseGnoReturns = (result: string):Array<unknown> => {
const ret=[];
const values = result.split("\n");
for (let i=0; i<values.length; i++) {
let value=JSON.parse(values[i].substring(1).split(" ").slice(0,-1).join(" "));
ret.push(value);
}
return ret;
}
31 changes: 31 additions & 0 deletions src/wallet/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
AccountWalletOption,
BroadcastTransactionMap,
CreateWalletOptions,
Provider,
Tx,
TxFee,
Wallet,
Expand All @@ -11,16 +12,39 @@ 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';
import { GnoProvider } from '../provider';

/**
* GnoWallet is an extension of the TM2 wallet with
* specific functionality for Gno chains
*/
export class GnoWallet extends Wallet {
protected provider:GnoProvider
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<T extends Realm | Realm[]>(realms: T) {
const currentRealms = this.realms;

class AugmentedWallet extends this {
static realms = currentRealms.concat(realms);
}

if (Array.isArray(realms)) {
type Extension = UnionToIntersection<Return<T>['realm']>
return AugmentedWallet as typeof GnoWallet & Constructor<Extension>;
}

type Extension = Return<T>['realm']
return AugmentedWallet as typeof GnoWallet & Constructor<Extension>;
}
/**
* Generates a private key-based wallet, using a random seed
* @param {AccountWalletOption} options the account options
Expand Down Expand Up @@ -86,6 +110,13 @@ export class GnoWallet extends Wallet {

return gnoWallet;
};
/**
* Returns the connected provider, if any
* (Here to ensure correct GnoProvider inference)
*/
getProvider = (): GnoProvider => {
return this.provider;
};

/**
* Initiates a native currency transfer transaction between accounts
Expand Down