Skip to content

Commit

Permalink
feat: Add the MsgRun transaction execution function
Browse files Browse the repository at this point in the history
  • Loading branch information
jinoosss committed Feb 5, 2024
1 parent 8f81ffc commit 8a84689
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 13 deletions.
11 changes: 11 additions & 0 deletions proto/gno/vm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ message MsgAddPackage {
string deposit = 3;
}

// MsgRun is the execute arbitrary Gno code tx message,
// denoted as "m_run"
message MsgRun {
// the bech32 address of the caller
string caller = 1;
// the amount of funds to be deposited to the package, if any ("<amount><denomination>")
string send = 2;
// the package being execute
MemPackage package = 3;
}

// MemPackage is the metadata information tied to
// package / realm deployment
message MemPackage {
Expand Down
135 changes: 124 additions & 11 deletions src/proto/gno/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ export interface MsgAddPackage {
deposit: string;
}

/**
* MsgRun is the execute arbitrary Gno code tx message,
* denoted as "m_run"
*/
export interface MsgRun {
/** the bech32 address of the caller */
caller: string;
/** the amount of funds to be deposited to the package, if any ("<amount><denomination>") */
send: string;
/** the package being execute */
package?: MemPackage | undefined;
}

/**
* MemPackage is the metadata information tied to
* package / realm deployment
Expand Down Expand Up @@ -291,6 +304,104 @@ export const MsgAddPackage = {
},
};

function createBaseMsgRun(): MsgRun {
return { caller: '', send: '', package: undefined };
}

export const MsgRun = {
encode(
message: MsgRun,
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.caller !== '') {
writer.uint32(10).string(message.caller);
}
if (message.send !== '') {
writer.uint32(18).string(message.send);
}
if (message.package !== undefined) {
MemPackage.encode(message.package, writer.uint32(26).fork()).ldelim();
}
return writer;
},

decode(input: _m0.Reader | Uint8Array, length?: number): MsgRun {
const reader =
input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseMsgRun();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}

message.caller = reader.string();
continue;
case 2:
if (tag !== 18) {
break;
}

message.send = reader.string();
continue;
case 3:
if (tag !== 26) {
break;
}

message.package = MemPackage.decode(reader, reader.uint32());
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},

fromJSON(object: any): MsgRun {
return {
caller: isSet(object.caller) ? String(object.caller) : '',
send: isSet(object.send) ? String(object.send) : '',
package: isSet(object.package)
? MemPackage.fromJSON(object.package)
: undefined,
};
},

toJSON(message: MsgRun): unknown {
const obj: any = {};
if (message.caller !== '') {
obj.caller = message.caller;
}
if (message.send !== '') {
obj.send = message.send;
}
if (message.package !== undefined) {
obj.package = MemPackage.toJSON(message.package);
}
return obj;
},

create<I extends Exact<DeepPartial<MsgRun>, I>>(base?: I): MsgRun {
return MsgRun.fromPartial(base ?? ({} as any));
},
fromPartial<I extends Exact<DeepPartial<MsgRun>, I>>(object: I): MsgRun {
const message = createBaseMsgRun();
message.caller = object.caller ?? '';
message.send = object.send ?? '';
message.package =
object.package !== undefined && object.package !== null
? MemPackage.fromPartial(object.package)
: undefined;
return message;
},
};

function createBaseMemPackage(): MemPackage {
return { name: '', path: '', files: [] };
}
Expand Down Expand Up @@ -478,21 +589,23 @@ type Builtin =
export type DeepPartial<T> = T extends Builtin
? T
: T extends Long
? string | number | Long
: T extends Array<infer U>
? Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
? string | number | Long
: T extends Array<infer U>
? Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin
? P
: P & { [K in keyof P]: Exact<P[K], I[K]> } & {
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
};
: P &
{ [K in keyof P]: Exact<P[K], I[K]> } &
{
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
};

if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
Expand Down
1 change: 1 addition & 0 deletions src/wallet/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export enum MsgEndpoint {
MSG_SEND = '/bank.MsgSend',
MSG_ADD_PKG = '/vm.m_addpkg',
MSG_CALL = '/vm.m_call',
MSG_RUN = '/vm.m_run',
}
39 changes: 37 additions & 2 deletions src/wallet/utility/utility.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Any, MsgAddPackage, MsgCall, MsgSend } from '../../proto';
import { Any, MemPackage, MsgAddPackage, MsgCall, MsgSend } from '../../proto';
import { MsgRun } from '../../proto/gno/vm';
import { MsgEndpoint } from '../endpoints';

/**
Expand Down Expand Up @@ -49,12 +50,46 @@ export const decodeTxMessages = (messages: Any[]): any[] => {
...MsgSend.decode(m.value),
};
case MsgEndpoint.MSG_ADD_PKG:
const msgAddPkg = MsgAddPackage.decode(m.value);
return {
'@type': m.typeUrl,
...MsgAddPackage.decode(m.value),
...msgAddPkg,
package: msgAddPkg.package
? mapToStdMemPackage(msgAddPkg.package)
: undefined,
};
case MsgEndpoint.MSG_RUN:
const msgRun = MsgRun.decode(m.value);
return {
'@type': m.typeUrl,
...msgRun,
package: msgRun.package
? mapToStdMemPackage(msgRun.package)
: undefined,
};
default:
throw new Error(`unsupported message type ${m.typeUrl}`);
}
});
};

interface StdMemPackage {
Name: string;
Path: string;
Files: {
Name: string;
Body: string;
}[];
}

const mapToStdMemPackage = (memPackage: MemPackage): StdMemPackage => {
const { name, path, files } = memPackage;
return {
Name: name,
Path: path,
Files: files.map((file) => ({
Name: file.name,
Body: file.body,
})),
};
};
55 changes: 55 additions & 0 deletions src/wallet/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Long from 'long';
import { MemPackage, MsgAddPackage, MsgCall, MsgSend } from '../proto';
import { MsgEndpoint } from './endpoints';
import { LedgerConnector } from '@cosmjs/ledger-amino';
import { MsgRun } from '../proto/gno/vm';

/**
* GnoWallet is an extension of the TM2 wallet with
Expand Down Expand Up @@ -254,4 +255,58 @@ export class GnoWallet extends Wallet {
// Send the transaction
return this.sendTransaction(signedTx, endpoint);
};

/**
* Executes arbitrary Gno code
* @param {MemPackage} gnoPackage the package being execute
* @param {TransactionEndpoint} endpoint the transaction broadcast type (sync / commit)
* @param {Map<string, number>} [funds] the denomination -> value map for funds, if any
* @param {TxFee} [fee] the custom transaction fee, if any
*/
executePackage = async <K extends keyof BroadcastTransactionMap>(
gnoPackage: MemPackage,
endpoint: K,
funds?: Map<string, number>,
fee?: TxFee
): Promise<BroadcastTransactionMap[K]['result']> => {
// Convert the funds into the correct representation
const amount: string = fundsToCoins(funds);

// Fetch the wallet address
const caller: string = await this.getAddress();

// Construct the transaction fee
const txFee: TxFee = fee
? fee
: {
gasWanted: new Long(60000),
gasFee: defaultTxFee,
};

// Prepare the Msg
const runMsg: MsgRun = {
caller,
send: amount,
package: gnoPackage,
};

// Construct the transfer transaction
const tx: Tx = {
messages: [
{
typeUrl: MsgEndpoint.MSG_RUN,
value: MsgRun.encode(runMsg).finish(),
},
],
fee: txFee,
memo: '',
signatures: [], // No signature yet
};

// Sign the transaction
const signedTx: Tx = await this.signTransaction(tx, decodeTxMessages);

// Send the transaction
return this.sendTransaction(signedTx, endpoint);
};
}

0 comments on commit 8a84689

Please sign in to comment.