Skip to content

Commit

Permalink
[api] Return support of old vouchers (#1477)
Browse files Browse the repository at this point in the history
  • Loading branch information
osipov-mit authored Jan 25, 2024
1 parent 4d33de1 commit 6282c62
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 16 deletions.
8 changes: 8 additions & 0 deletions api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.36.2

_01/25/2024_

### Changes
https://github.com/gear-tech/gear-js/pull/1477
- Return support of old vouchers

## 0.36.1

_01/23/2024_
Expand Down
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gear-js/api",
"version": "0.36.1",
"version": "0.36.2",
"description": "A JavaScript library that provides functionality to connect GEAR Component APIs.",
"main": "cjs/index.js",
"module": "index.js",
Expand Down
36 changes: 27 additions & 9 deletions api/src/Voucher.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { stringToU8a, u8aToU8a } from '@polkadot/util';
import { BalanceOf } from '@polkadot/types/interfaces';
import { HexString } from '@polkadot/util/types';
import { ISubmittableResult } from '@polkadot/types/types';
Expand All @@ -7,8 +6,9 @@ import { SubmittableExtrinsic } from '@polkadot/api/types';
import { blake2AsHex } from '@polkadot/util-crypto';

import { ICallOptions, IUpdateVoucherParams, IVoucherDetails, PalletGearVoucherInternalVoucherInfo } from './types';
import { decodeAddress, generateVoucherId } from './utils';
import { GearTransaction } from './Transaction';
import { generateVoucherId } from './utils';
import { SPEC_VERSION } from './consts';

export class GearVoucher extends GearTransaction {
/**
Expand Down Expand Up @@ -65,9 +65,7 @@ export class GearVoucher extends GearTransaction {
program: HexString,
value: number | bigint | string,
): { extrinsic: SubmittableExtrinsic<'promise', ISubmittableResult>; voucherId: HexString } {
const whoU8a = u8aToU8a(to);
const programU8a = u8aToU8a(program);
const id = Uint8Array.from([...stringToU8a('modlpy/voucher__'), ...whoU8a, ...programU8a]);
const id = generateVoucherId(to, program);

const voucherId = blake2AsHex(id, 256);
this.extrinsic = this._api.tx.gearVoucher.issue.call(this, to, program, value);
Expand Down Expand Up @@ -218,6 +216,16 @@ export class GearVoucher extends GearTransaction {
* @returns
*/
async exists(accountId: string, programId: HexString): Promise<boolean> {
if (this._api.specVersion < SPEC_VERSION.V1100) {
const id = generateVoucherId(decodeAddress(accountId), programId);

const balance = await this._api.balance.findOut(id);
if (balance.eqn(0)) {
return false;
}
return true;
}

const keyPrefixes = this._api.query.gearVoucher.vouchers.keyPrefix(accountId);

const keysPaged = await this._api.rpc.state.getKeysPaged(keyPrefixes, 1000, keyPrefixes);
Expand Down Expand Up @@ -245,8 +253,8 @@ export class GearVoucher extends GearTransaction {
* @param accountId
* @returns
*/
async getAllForAccount(accountId: string): Promise<Record<string, string[]>> {
const result: Record<string, string[]> = {};
async getAllForAccount(accountId: string, programId?: HexString): Promise<Record<string, IVoucherDetails>> {
const result: Record<string, IVoucherDetails> = {};

const keyPrefix = this._api.query.gearVoucher.vouchers.keyPrefix(accountId);

Expand All @@ -270,9 +278,19 @@ export class GearVoucher extends GearTransaction {
return;
}

const programs = typedItem.unwrap().programs.unwrapOrDefault().toJSON() as string[];
const details = typedItem.unwrap();
const programs = details.programs.unwrapOrDefault().toJSON() as string[];

if (details.programs.isSome && programId && !programs.includes(programId)) {
return;
}

result[voucherId] = programs;
result[voucherId] = {
owner: details.owner.toHex(),
programs,
expiry: details.expiry.toNumber(),
codeUploading: details.codeUploading.isTrue,
};
});

return result;
Expand Down
19 changes: 16 additions & 3 deletions api/src/utils/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CreateType } from '../metadata';
import { GearApi } from 'GearApi';
import { SPEC_VERSION } from '../consts';

const VOUCHER_PREFIX_BEFORE_1100 = stringToU8a('modlpy/voucher__');
const VOUCHER_PREFIX = stringToU8a('voucher');

export function generateCodeHash(code: Buffer | Uint8Array | HexString): HexString {
Expand Down Expand Up @@ -38,8 +39,20 @@ export function generateProgramId(
return blake2AsHex(id, 256);
}

export function generateVoucherId(nonce: U8aLike): HexString {
const nonceU8a = u8aToU8a(nonce);
const id = Uint8Array.from([...VOUCHER_PREFIX, ...nonceU8a]);
/**
* @deprecated
*/
export function generateVoucherId(who: HexString, programId: HexString): HexString;
export function generateVoucherId(nonce: U8aLike): HexString;
export function generateVoucherId(nonceOrWho: U8aLike | HexString, programId?: HexString): HexString {
const [nonce, who] = typeof nonceOrWho === 'string' && programId ? [undefined, nonceOrWho] : [nonceOrWho, undefined];
if (nonce) {
const nonceU8a = u8aToU8a(nonce);
const id = Uint8Array.from([...VOUCHER_PREFIX, ...nonceU8a]);
return blake2AsHex(id, 256);
}
const whoU8a = u8aToU8a(who);
const programU8a = u8aToU8a(programId);
const id = Uint8Array.from([...VOUCHER_PREFIX_BEFORE_1100, ...whoU8a, ...programU8a]);
return blake2AsHex(id, 256);
}
8 changes: 5 additions & 3 deletions api/test/Voucher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('Voucher', () => {
expect(txData).toHaveProperty('holder');
expect(txData).toHaveProperty('program');
expect(txData).toHaveProperty('value');
expect(Object.keys(txData)).toHaveLength(3);
expect(Object.keys(txData.toJSON())).toHaveLength(3);
expect(txData.holder.toHuman()).toBe(charlie.address);
expect(txData.program.toHex()).toBe(programId);
expect(txData.value.toNumber()).toBe(100_000_000_000_000);
Expand Down Expand Up @@ -121,8 +121,10 @@ describe('Voucher', () => {
test('Get all vouchers for account', async () => {
const vouchers = await api.voucher.getAllForAccount(charlie.address);
expect(Object.keys(vouchers)).toHaveLength(1);
expect(vouchers[voucher]).toHaveLength(1);
expect(vouchers[voucher][0]).toBe(programId);
expect(vouchers[voucher]).toHaveProperty('programs', [programId]);
expect(vouchers[voucher]).toHaveProperty('owner', decodeAddress(alice.address));
expect(vouchers[voucher]).toHaveProperty('expiry', validUpTo);
expect(vouchers[voucher]).toHaveProperty('codeUploading', true);
});

test('Get voucher details', async () => {
Expand Down

0 comments on commit 6282c62

Please sign in to comment.