Skip to content

Commit

Permalink
feat(js): support vouchers in transaction builder (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
osipov-mit authored May 23, 2024
1 parent 04e8c30 commit fbe22b4
Show file tree
Hide file tree
Showing 18 changed files with 211 additions and 11 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/ci-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ jobs:

- name: "Prepare: build rmrk"
run: |
cargo build --manifest-path=examples/rmrk/catalog/wasm/Cargo.toml
cargo build --manifest-path=examples/rmrk/resource/wasm/Cargo.toml
cargo build --manifest-path=examples/rmrk/catalog/wasm/Cargo.toml --release
cargo build --manifest-path=examples/rmrk/resource/wasm/Cargo.toml --release
cargo build --manifest-path=examples/ping/wasm/Cargo.toml --release
- name: "Prepare: build rmrk client lib"
working-directory: js
run: |
node lib/app.js generate ../examples/rmrk/catalog/wasm/rmrk-catalog.idl -o ./test/rmrk-catalog
node lib/app.js generate ../examples/rmrk/resource/wasm/rmrk-resource.idl -o ./test/rmrk-resource
node lib/app.js generate ../examples/ping/wasm/ping.idl -o ./test/ping
- name: "Prepare: download Gear node"
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
js/lib/
js/parser.wasm
js/test/rmrk-*/
js/test/ping/

node_modules/
target/
Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ members = [
"examples/references/wasm",
"examples/no-svcs-prog/app",
"examples/no-svcs-prog/wasm",
"examples/ping/app",
"examples/ping/wasm",
"examples/puppeteer/app",
"examples/puppeteer/wasm",
"examples/rmrk/catalog/app",
Expand Down
3 changes: 3 additions & 0 deletions examples/ping/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# simple ping example


7 changes: 7 additions & 0 deletions examples/ping/app/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "ping-app"
version = "0.1.0"
edition = "2021"

[dependencies]
sails-rtl.workspace = true
20 changes: 20 additions & 0 deletions examples/ping/app/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#![no_std]

use sails_rtl::gstd::gprogram;
use service::PingService;

pub mod service;

#[derive(Default)]
pub struct Program;

#[gprogram]
impl Program {
pub fn new() -> Self {
Self
}

pub fn ping(&self) -> service::PingService {
PingService::new()
}
}
19 changes: 19 additions & 0 deletions examples/ping/app/src/service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use sails_rtl::{gstd::gservice, prelude::*};

#[derive(Default)]
pub struct PingService {}

#[gservice]
impl PingService {
pub fn new() -> Self {
Self {}
}

pub fn ping(&mut self, input: String) -> Result<String, String> {
if input != "ping" {
Err("Invalid input".into())
} else {
Ok("pong".into())
}
}
}
13 changes: 13 additions & 0 deletions examples/ping/wasm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "ping"
version = "0.1.0"
edition = "2021"

[dependencies]
ping-app = { path = "../app" }
sails-rtl.workspace = true

[build-dependencies]
gwasm-builder.workspace = true
ping-app = { path = "../app" }
sails-idl-gen.workspace = true
15 changes: 15 additions & 0 deletions examples/ping/wasm/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use ping_app::Program;
use sails_idl_gen::program;
use std::{env, fs::File, path::PathBuf};

fn main() {
gwasm_builder::build();

let manifest_dir_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());

let idl_file_path = manifest_dir_path.join("ping.idl");

let idl_file = File::create(idl_file_path).unwrap();

program::generate_idl::<Program>(idl_file).unwrap();
}
8 changes: 8 additions & 0 deletions examples/ping/wasm/ping.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
constructor {
New : ();
};

service Ping {
Ping : (input: str) -> result (str, str);
};

4 changes: 4 additions & 0 deletions examples/ping/wasm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![no_std]

#[cfg(target_arch = "wasm32")]
pub use ping_app::wasm::*;
2 changes: 1 addition & 1 deletion js/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const config: Config.InitialOptions = {
transform: {
'^.+\\.tsx?$': ['ts-jest', { useESM: true }],
},
testTimeout: 30000,
testTimeout: 15_000,
};

export default config;
21 changes: 20 additions & 1 deletion js/src/transaction-builder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GearApi, HexString, MessageQueuedData, decodeAddress } from '@gear-js/api';
import { GearApi, HexString, ICallOptions, MessageQueuedData, decodeAddress } from '@gear-js/api';
import { SignerOptions, SubmittableExtrinsic } from '@polkadot/api/types';
import { IKeyringPair, ISubmittableResult } from '@polkadot/types/types';
import { TypeRegistry, u128, u64 } from '@polkadot/types';
Expand All @@ -15,6 +15,7 @@ export class TransactionBuilder<ResponseType> {
private _account: string | IKeyringPair;
private _signerOptions: Partial<SignerOptions>;
private _tx: SubmittableExtrinsic<'promise', ISubmittableResult>;
private _voucher: string;
public readonly programId: HexString;

constructor(
Expand Down Expand Up @@ -235,10 +236,28 @@ export class TransactionBuilder<ResponseType> {
return this;
}

/**
* ## Use voucher for transaction
* @param id Voucher id
*/
public withVoucher(id: HexString) {
if (this._tx.method.method !== 'sendMessage') {
throw new Error('Voucher can be used only with sendMessage extrinsics');
}

this._voucher = id;
return this;
}

/**
* ## Sign and send transaction
*/
public async signAndSend(): Promise<IMethodReturnType<ResponseType>> {
if (this._voucher) {
const callParams: ICallOptions = { SendMessage: this._tx };
this._tx = this._api.voucher.call(this._voucher, callParams);
}

const { msgId, blockHash } = await new Promise<{ msgId: HexString; blockHash: HexString }>((resolve, reject) =>
this._tx
.signAndSend(this._account, this._signerOptions, ({ events, status }) => {
Expand Down
2 changes: 1 addition & 1 deletion js/test/modify-import.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as fs from 'fs';

const filesToModify = ['test/rmrk-catalog/lib.ts', 'test/rmrk-resource/lib.ts'];
const filesToModify = ['test/rmrk-catalog/lib.ts', 'test/rmrk-resource/lib.ts', 'test/ping/lib.ts'];

for (const path of filesToModify) {
const data = fs.readFileSync(path, 'utf8').replace(`from 'sails-js'`, `from '../../lib/index.js'`);
Expand Down
67 changes: 67 additions & 0 deletions js/test/ping.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { GearApi, HexString, MessageQueued, VoucherIssued, decodeAddress } from '@gear-js/api';
import { KeyringPair } from '@polkadot/keyring/types';
import { waitReady } from '@polkadot/wasm-crypto';
import { Keyring } from '@polkadot/api';
import { readFileSync } from 'fs';

import { Sails } from '../lib';
import { Program } from './ping/lib';

let sails: Sails;
let api: GearApi;
let alice: KeyringPair;
let aliceRaw: HexString;
let charlie: KeyringPair;
let charlieRaw: HexString;
let code: Buffer;

const CATALOG_WASM_PATH = '../target/wasm32-unknown-unknown/release/ping.opt.wasm';

beforeAll(async () => {
sails = await Sails.new();
api = await GearApi.create({ providerAddress: 'ws://127.0.0.1:9944' });
await waitReady();
const keyring = new Keyring({ type: 'sr25519' });
alice = keyring.addFromUri('//Alice');
aliceRaw = decodeAddress(alice.address);
charlie = keyring.addFromUri('//Charlie');
charlieRaw = decodeAddress(charlie.address);
code = readFileSync(CATALOG_WASM_PATH);
});

afterAll(async () => {
await api.disconnect();
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});
});

describe('Ping', () => {
let program: Program;

test('create program', async () => {
program = new Program(api);

const transaction = await program.newCtorFromCode(code).withAccount(alice).calculateGas();

const { msgId, blockHash, response } = await transaction.signAndSend();

expect(msgId).toBeDefined();
expect(blockHash).toBeDefined();

await response();
});

test('ping', async () => {
const transaction = await program.ping.ping('ping').withAccount(alice).calculateGas();

const { msgId, blockHash, response } = await transaction.signAndSend();

expect(msgId).toBeDefined();
expect(blockHash).toBeDefined();

const result = await response();

expect(result).toHaveProperty('ok', 'pong');
});
});
13 changes: 8 additions & 5 deletions js/test/rmrk-catalog.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GearApi, HexString, MessageQueued, decodeAddress } from '@gear-js/api';
import { GearApi, HexString, decodeAddress } from '@gear-js/api';
import { KeyringPair } from '@polkadot/keyring/types';
import { waitReady } from '@polkadot/wasm-crypto';
import { Keyring } from '@polkadot/api';
Expand All @@ -14,13 +14,14 @@ let aliceRaw: HexString;
let code: Buffer;

const IDL_PATH = '../examples/rmrk/catalog/wasm/rmrk-catalog.idl';
const CATALOG_WASM_PATH = '../target/wasm32-unknown-unknown/debug/rmrk_catalog.opt.wasm';
const CATALOG_WASM_PATH = '../target/wasm32-unknown-unknown/release/rmrk_catalog.opt.wasm';

beforeAll(async () => {
sails = await Sails.new();
api = await GearApi.create({ providerAddress: 'ws://127.0.0.1:9944' });
await waitReady();
alice = new Keyring().addFromUri('//Alice', {}, 'sr25519');
const keyring = new Keyring({ type: 'sr25519' });
alice = keyring.addFromUri('//Alice');
aliceRaw = decodeAddress(alice.address);
code = readFileSync(CATALOG_WASM_PATH);
});
Expand All @@ -40,7 +41,9 @@ describe('RMRK catalog', () => {

test('upload catalog', async () => {
sails.setApi(api);
const transaction = await sails.ctors.New.fromCode(code).withAccount(alice).calculateGas();
const transaction = await sails.ctors.New.fromCode(code)
.withAccount(alice)
.withGas(api.blockGasLimit.toBigInt() / 2n);
const { response } = await transaction.signAndSend();
await response();
});
Expand Down Expand Up @@ -170,7 +173,7 @@ describe('RMRK generated', () => {
test('add equippables', async () => {
expect(programCreated).toBeTruthy();
expect(program).toBeDefined();
const transaction = await program.rmrkCatalog.addEquippables(3, [aliceRaw]);
const transaction = program.rmrkCatalog.addEquippables(3, [aliceRaw]);

await transaction.withAccount(alice).calculateGas();

Expand Down
2 changes: 1 addition & 1 deletion js/test/rmrk-resource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let code: Buffer;
let resourceId: HexString;

const IDL_PATH = '../examples/rmrk/resource/wasm/rmrk-resource.idl';
const RESOURCE_WASM_PATH = '../target/wasm32-unknown-unknown/debug/rmrk_resource.opt.wasm';
const RESOURCE_WASM_PATH = '../target/wasm32-unknown-unknown/release/rmrk_resource.opt.wasm';

beforeAll(async () => {
sails = await Sails.new();
Expand Down

0 comments on commit fbe22b4

Please sign in to comment.