Skip to content

Commit

Permalink
feat: refactor all js number and bn.js usages in Clarity integer …
Browse files Browse the repository at this point in the history
…values to native bigint
  • Loading branch information
zone117x authored and reedrosenbluth committed Jul 26, 2021
1 parent 53dd641 commit 1f78339
Show file tree
Hide file tree
Showing 24 changed files with 562 additions and 505 deletions.
4 changes: 2 additions & 2 deletions packages/bns/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export interface GetNamespacePriceOptions {
export async function getNamespacePrice({
namespace,
network,
}: GetNamespacePriceOptions): Promise<BN> {
}: GetNamespacePriceOptions): Promise<bigint> {
const bnsFunctionName = 'get-namespace-price';

// Create a random address as input to read-only function call
Expand Down Expand Up @@ -245,7 +245,7 @@ export interface GetNamePriceOptions {
export async function getNamePrice({
fullyQualifiedName,
network,
}: GetNamePriceOptions): Promise<BN> {
}: GetNamePriceOptions): Promise<bigint> {
const bnsFunctionName = 'get-name-price';
const { subdomain, namespace, name } = decodeFQN(fullyQualifiedName);
if (subdomain) {
Expand Down
4 changes: 2 additions & 2 deletions packages/bns/tests/bns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ test('getNamespacePrice', async () => {
network
};

expect(result).toEqual(new BN(10));
expect(result.toString()).toEqual('10');
expect(callReadOnlyFunction).toHaveBeenCalledTimes(1);
expect(callReadOnlyFunction).toHaveBeenCalledWith(expectedReadOnlyFunctionCallOptions);
});
Expand Down Expand Up @@ -303,7 +303,7 @@ test('getNamePrice', async () => {
network
};

expect(result).toEqual(new BN(10));
expect(result.toString()).toEqual('10');
expect(callReadOnlyFunction).toHaveBeenCalledTimes(1);
expect(callReadOnlyFunction).toHaveBeenCalledWith(expectedReadOnlyFunctionCallOptions);
});
Expand Down
1 change: 1 addition & 0 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"dependencies": {
"@types/node": "^14.14.43",
"bn.js": "^5.2.0",
"buffer": "^6.0.3",
"cross-fetch": "^3.1.4"
},
Expand Down
69 changes: 69 additions & 0 deletions packages/common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Buffer as BufferPolyfill } from 'buffer/';
// so export using the type definition from NodeJS (@types/node).
import type { Buffer as NodeJSBuffer } from 'buffer';

import BN from 'bn.js';

const AvailableBufferModule: typeof NodeJSBuffer =
// eslint-disable-next-line node/prefer-global/buffer
typeof Buffer !== 'undefined' ? Buffer : (BufferPolyfill as any);
Expand Down Expand Up @@ -328,3 +330,70 @@ export function getGlobalObjects<K extends Extract<keyof Window, string>>(
}
return result;
}

export type IntegerType = number | string | bigint | Uint8Array | BufferPolyfill | BN;

/*
export function BigInt(value: any): bigint {
let bigInt = BigInt(value);
bigInt = Object.assign(bigInt, { toJSON: () => bigInt.toString() });
return bigInt;
}
*/

// eslint-disable-next-line node/prefer-global/buffer
export function intToBytes(value: IntegerType, signed: boolean, byteLength: number): Buffer {
return intToBN(value, signed).toArrayLike(AvailableBufferModule, 'be', byteLength);
}

export function intToBN(value: IntegerType, signed: boolean): BN {
const bigInt = intToBigInt(value, signed);
return new BN(bigInt.toString());
}

export function intToBigInt(value: IntegerType, signed: boolean): bigint {
if (typeof value === 'number') {
if (!Number.isInteger(value)) {
throw new RangeError(`Invalid value. Values of type 'number' must be an integer.`);
}
return BigInt(value);
}
if (typeof value === 'string') {
// If hex string then convert to buffer then fall through to the buffer condition
if (value.toLowerCase().startsWith('0x')) {
// Trim '0x' hex-prefix
let hex = value.slice(2);
// Allow odd-length strings like `0xf` -- some libs output these, or even just `0x${num.toString(16)}`
hex = hex.padStart(hex.length + (hex.length % 2), '0');
value = AvailableBufferModule.from(hex, 'hex');
} else {
try {
return BigInt(value);
} catch (error) {
if (error instanceof SyntaxError) {
throw new RangeError(`Invalid value. String integer '${value}' is not finite.`)
}
}
}
}
if (typeof value === 'bigint') {
return value;
}
if (value instanceof Uint8Array || BufferPolyfill.isBuffer(value)) {
if (signed) {
// Allow byte arrays smaller than 128-bits to be passed.
// This allows positive signed ints like `0x08` (8) or negative signed
// ints like `0xf8` (-8) to be passed without having to pad to 16 bytes.
const bn = new BN(value, 'be').fromTwos(value.byteLength * 8);
return BigInt(bn.toString());
} else {
return BigInt(new BN(value, 'be').toString());
}
}
if (value instanceof BN || BN.isBN(value)) {
return BigInt(value.toString());
}
throw new TypeError(
`Invalid value type. Must be a number, bigint, integer-string, hex-string, BN.js instance, or Buffer.`
);
}
6 changes: 3 additions & 3 deletions packages/keychain/src/wallet/signer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-ignore
import { Buffer } from '@stacks/common';
import { Buffer, IntegerType } from '@stacks/common';
import {
makeContractCall,
makeContractDeploy,
Expand All @@ -22,7 +22,7 @@ interface ContractCallOptions {
functionName: string;
functionArgs: ClarityValue[];
version: TransactionVersion;
nonce: number;
nonce: IntegerType;
postConditions?: PostCondition[];
postConditionMode?: PostConditionMode;
network?: StacksNetwork;
Expand Down Expand Up @@ -100,7 +100,7 @@ export class WalletSigner {
functionName,
functionArgs,
senderKey: this.getSTXPrivateKey().toString('hex'),
nonce: new BN(nonce),
nonce: nonce,
network: this.getNetwork(),
postConditionMode,
postConditions,
Expand Down
26 changes: 11 additions & 15 deletions packages/stacking/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,11 @@ export class StackingClient {
/**
* Get account balance
*
* @returns {Promise<BN>} that resolves to a BigNum if the operation succeeds
* @returns promise resolves to a bigint if the operation succeeds
*/
async getAccountBalance(): Promise<BN> {
async getAccountBalance(): Promise<bigint> {
return this.getAccountStatus().then(res => {
let balanceHex = res.balance;
if (res.balance.startsWith('0x')) {
balanceHex = res.balance.substr(2);
}
return new BN(balanceHex, 'hex');
return BigInt(res.balance);
});
}

Expand Down Expand Up @@ -314,9 +310,9 @@ export class StackingClient {
* @returns {Promise<boolean>} that resolves to a bool if the operation succeeds
*/
async hasMinimumStx(): Promise<boolean> {
const balance: BN = await this.getAccountBalance();
const min: BN = new BN((await this.getPoxInfo()).min_amount_ustx.toString());
return balance.gte(min);
const balance = await this.getAccountBalance();
const min = BigInt((await this.getPoxInfo()).min_amount_ustx);
return balance >= min;
}

/**
Expand All @@ -327,7 +323,7 @@ export class StackingClient {
* @returns {Promise<StackingEligibility>} that resolves to a StackingEligibility object if the operation succeeds
*/
async canStack({ poxAddress, cycles }: CanLockStxOptions): Promise<StackingEligibility> {
const balancePromise: Promise<BN> = this.getAccountBalance();
const balancePromise: Promise<bigint> = this.getAccountBalance();
const poxInfoPromise = this.getPoxInfo();

return Promise.all([balancePromise, poxInfoPromise])
Expand Down Expand Up @@ -736,8 +732,8 @@ export class StackingClient {
stacked: true,
details: {
amount_microstx: amountMicroStx.value.toString(),
first_reward_cycle: firstRewardCycle.value.toNumber(),
lock_period: lockPeriod.value.toNumber(),
first_reward_cycle: Number(firstRewardCycle.value),
lock_period: Number(lockPeriod.value),
unlock_height: account.unlock_height,
pox_address: {
version: version.buffer,
Expand All @@ -761,9 +757,9 @@ export class StackingClient {
* @returns {StacksTransaction} that resolves to a transaction object if the operation succeeds
*/
modifyLockTxFee({ tx, amountMicroStx }: { tx: StacksTransaction; amountMicroStx: BN }) {
const fee = tx.auth.getFee() as BN;
const fee = tx.auth.getFee();
(tx.payload as ContractCallPayload).functionArgs[0] = uintCV(
new BN(amountMicroStx.toString(10), 10).sub(fee).toArrayLike(Buffer)
amountMicroStx.sub(new BN(fee.toString()))
);
return tx;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/storage/tests/storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ test('deleteFile', async () => {

const appConfig = new AppConfig(['store_write'], 'http://localhost:3000');
const userSession = new UserSession({ appConfig });
userSession.store.getSessionData().userData = <any>{
userSession.store.getSessionData().userData = {
gaiaHubConfig,
};
} as any;

const deleteFromGaiaHub = jest.fn();
jest.mock('../src/hub', () => ({
Expand Down

0 comments on commit 1f78339

Please sign in to comment.