Skip to content

Commit

Permalink
Merge pull request #933 from near/NAJ-106
Browse files Browse the repository at this point in the history
Migrating nonce type from number to string
  • Loading branch information
hcho112 authored Sep 6, 2022
2 parents fcbd34c + 4f77940 commit 96785cb
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 15 deletions.
19 changes: 10 additions & 9 deletions packages/near-api-js/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
ViewStateResult,
AccountView,
AccessKeyView,
AccessKeyViewRaw,
CodeResult,
AccessKeyList,
AccessKeyInfoView,
Expand Down Expand Up @@ -202,7 +203,7 @@ export class Account {
const block = await this.connection.provider.block({ finality: 'final' });
const blockHash = block.header.hash;

const nonce = ++accessKey.nonce;
const nonce = accessKey.nonce.add(new BN(1));
return await signTransaction(
receiverId, nonce, actions, baseDecode(blockHash), this.connection.signer, this.accountId, this.connection.networkId
);
Expand Down Expand Up @@ -294,13 +295,18 @@ export class Account {
}

try {
const accessKey = await this.connection.provider.query<AccessKeyView>({
const rawAccessKey = await this.connection.provider.query<AccessKeyViewRaw>({
request_type: 'view_access_key',
account_id: this.accountId,
public_key: publicKey.toString(),
finality: 'optimistic'
});

// store nonce as BN to preserve precision on big number
const accessKey = {
...rawAccessKey,
nonce: new BN(rawAccessKey.nonce),
};
// this function can be called multiple times and retrieve the same access key
// this checks to see if the access key was already retrieved and cached while
// the above network call was in flight. To keep nonce values in line, we return
Expand Down Expand Up @@ -580,13 +586,8 @@ export class Account {
account_id: this.accountId,
finality: 'optimistic'
});
// A breaking API change introduced extra information into the
// response, so it now returns an object with a `keys` field instead
// of an array: https://github.com/nearprotocol/nearcore/pull/1789
if (Array.isArray(response)) {
return response;
}
return response.keys;
// Replace raw nonce into a new BN
return response?.keys?.map((key) => ({ ...key, access_key: { ...key.access_key, nonce: new BN(key.access_key.nonce) } }));
}

/**
Expand Down
9 changes: 7 additions & 2 deletions packages/near-api-js/src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { SignedTransaction } from '../transaction';
import BN from 'bn.js';

export interface SyncInfo {
latest_block_hash: string;
Expand Down Expand Up @@ -181,7 +182,7 @@ export interface Chunk {
export interface Transaction {
actions: Array<any>;
hash: string;
nonce: bigint;
nonce: BN;
public_key: string;
receiver_id: string;
signature: string;
Expand Down Expand Up @@ -352,10 +353,14 @@ export interface FunctionCallPermissionView {
method_names: string[];
};
}
export interface AccessKeyView extends QueryResponseKind {
export interface AccessKeyViewRaw extends QueryResponseKind {
nonce: number;
permission: 'FullAccess' | FunctionCallPermissionView;
}
export interface AccessKeyView extends QueryResponseKind {
nonce: BN;
permission: 'FullAccess' | FunctionCallPermissionView;
}

export interface AccessKeyInfoView {
public_key: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/near-api-js/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export class Signature extends Assignable {
export class Transaction extends Assignable {
signerId: string;
publicKey: PublicKey;
nonce: number;
nonce: BN;
receiverId: string;
actions: Action[];
blockHash: Uint8Array;
Expand Down Expand Up @@ -220,7 +220,7 @@ export const SCHEMA = new Map<Class, any>([
]}],
]);

export function createTransaction(signerId: string, publicKey: PublicKey, receiverId: string, nonce: number, actions: Action[], blockHash: Uint8Array): Transaction {
export function createTransaction(signerId: string, publicKey: PublicKey, receiverId: string, nonce: BN | string | number, actions: Action[], blockHash: Uint8Array): Transaction {
return new Transaction({ signerId, publicKey, nonce, receiverId, actions, blockHash });
}

Expand All @@ -243,7 +243,7 @@ async function signTransactionObject(transaction: Transaction, signer: Signer, a
}

export async function signTransaction(transaction: Transaction, signer: Signer, accountId?: string, networkId?: string): Promise<[Uint8Array, SignedTransaction]>;
export async function signTransaction(receiverId: string, nonce: number, actions: Action[], blockHash: Uint8Array, signer: Signer, accountId?: string, networkId?: string): Promise<[Uint8Array, SignedTransaction]>;
export async function signTransaction(receiverId: string, nonce: BN, actions: Action[], blockHash: Uint8Array, signer: Signer, accountId?: string, networkId?: string): Promise<[Uint8Array, SignedTransaction]>;
export async function signTransaction(...args): Promise<[Uint8Array, SignedTransaction]> {
if (args[0].constructor === Transaction) {
const [ transaction, signer, accountId, networkId ] = args;
Expand Down
3 changes: 2 additions & 1 deletion packages/near-api-js/src/wallet-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { KeyPair, PublicKey } from './utils';
import { baseDecode } from 'borsh';
import { Connection } from './connection';
import { serialize } from 'borsh';
import BN from 'bn.js';

const LOGIN_WALLET_URL_SUFFIX = '/login/';
const MULTISIG_HAS_METHOD = 'add_request_and_confirm';
Expand Down Expand Up @@ -318,7 +319,7 @@ export class ConnectedWalletAccount extends Account {

const publicKey = PublicKey.from(accessKey.public_key);
// TODO: Cache & listen for nonce updates for given access key
const nonce = accessKey.access_key.nonce + 1;
const nonce = accessKey.access_key.nonce.add(new BN(1));
const transaction = createTransaction(this.accountId, publicKey, receiverId, nonce, actions, blockHash);
await this.walletConnection.requestSignTransactions({
transactions: [transaction],
Expand Down
52 changes: 52 additions & 0 deletions packages/near-api-js/test/serialize.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

const fs = require('fs');
const BN = require('bn.js');
const nearApi = require('../src/index');

class Test extends nearApi.utils.enums.Assignable {
Expand Down Expand Up @@ -111,4 +112,55 @@ describe('roundtrip test', () => {
});
}
}
});

describe('serialize and deserialize on different types of nonce', () => {
const actions = [
nearApi.transactions.transfer(1),
];
const blockHash = nearApi.utils.serialize.base_decode('244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM');
const targetNonce = new BN(1);
test('number typed nonce', async() => {
const transaction = nearApi.transactions.createTransaction(
'test.near',
nearApi.utils.PublicKey.fromString('Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC'),
'whatever.near',
1,
actions,
blockHash);
const serialized = transaction.encode();
expect(serialized.toString('hex')).toEqual('09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000301000000000000000000000000000000');
const deserialized = nearApi.transactions.Transaction.decode(serialized);
expect(deserialized.encode()).toEqual(serialized);
expect(deserialized.nonce.toString()).toEqual(targetNonce.toString());

});
test('string typed nonce', async() => {
const transaction = nearApi.transactions.createTransaction(
'test.near',
nearApi.utils.PublicKey.fromString('Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC'),
'whatever.near',
'1',
actions,
blockHash);
const serialized = transaction.encode();
expect(serialized.toString('hex')).toEqual('09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000301000000000000000000000000000000');
const deserialized = nearApi.transactions.Transaction.decode(serialized);
expect(deserialized.encode()).toEqual(serialized);
expect(deserialized.nonce.toString()).toEqual(targetNonce.toString());
});
test('BN typed nonce', async() => {
const transaction = nearApi.transactions.createTransaction(
'test.near',
nearApi.utils.PublicKey.fromString('Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC'),
'whatever.near',
new BN(1),
actions,
blockHash);
const serialized = transaction.encode();
expect(serialized.toString('hex')).toEqual('09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000301000000000000000000000000000000');
const deserialized = nearApi.transactions.Transaction.decode(serialized);
expect(deserialized.encode()).toEqual(serialized);
expect(deserialized.nonce.toString()).toEqual(targetNonce.toString());
});
});

0 comments on commit 96785cb

Please sign in to comment.