diff --git a/src/account.ts b/src/account.ts index 68ccf609..d371afdc 100644 --- a/src/account.ts +++ b/src/account.ts @@ -8,7 +8,7 @@ export class Account { /** * The address of the account. */ - readonly address: IAddress = new Address(); + readonly address: IAddress = Address.empty(); /** * The nonce of the account (the account sequence number). diff --git a/src/address.spec.ts b/src/address.spec.ts index 248b858a..48313ab0 100644 --- a/src/address.spec.ts +++ b/src/address.spec.ts @@ -17,7 +17,7 @@ describe("test address", () => { }); it("should create empty address", async () => { - let nobody = new Address(); + const nobody = Address.empty(); assert.isEmpty(nobody.hex()); assert.isEmpty(nobody.bech32()); @@ -55,4 +55,16 @@ describe("test address", () => { assert.isFalse(Address.isValid("xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); assert.isFalse(Address.isValid("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2")); }); + + it("should check whether isSmartContract", () => { + assert.isFalse( + Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").isSmartContract(), + ); + assert.isTrue( + Address.fromBech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqplllst77y4l").isSmartContract(), + ); + assert.isTrue( + Address.fromBech32("erd1qqqqqqqqqqqqqpgqxwakt2g7u9atsnr03gqcgmhcv38pt7mkd94q6shuwt").isSmartContract(), + ); + }); }); diff --git a/src/address.ts b/src/address.ts index 54601745..a5b3fda5 100644 --- a/src/address.ts +++ b/src/address.ts @@ -23,7 +23,7 @@ export class Address { /** * Creates an address object, given a raw string (whether a hex pubkey or a Bech32 address), a sequence of bytes, or another Address object. */ - public constructor(value?: Address | Buffer | string) { + public constructor(value: Address | Buffer | string) { if (!value) { return; } @@ -48,7 +48,7 @@ export class Address { } private static fromValidHex(value: string): Address { - let result = new Address(); + let result = Address.empty(); result.valueHex = value; return result; } @@ -91,10 +91,11 @@ export class Address { } /** - * Creates an empty address object + * Creates an empty address object. + * Generally speaking, this should not be used by client code (internal use only). */ static empty(): Address { - return new Address(); + return new Address(""); } /** @@ -109,12 +110,12 @@ export class Address { throw new errors.ErrAddressCannotCreate(value, err); } - let prefix = decoded.prefix; + const prefix = decoded.prefix; if (prefix != HRP) { throw new errors.ErrAddressBadHrp(HRP, prefix); } - let pubkey = Buffer.from(bech32.fromWords(decoded.words)); + const pubkey = Buffer.from(bech32.fromWords(decoded.words)); if (pubkey.length != PUBKEY_LENGTH) { throw new errors.ErrAddressCannotCreate(value); } @@ -138,9 +139,16 @@ export class Address { } /** - * Returns the hex representation of the address (pubkey) + * Use {@link toHex} instead. */ hex(): string { + return this.toHex(); + } + + /** + * Returns the hex representation of the address (pubkey) + */ + toHex(): string { if (this.isEmpty()) { return ""; } @@ -149,9 +157,16 @@ export class Address { } /** - * Returns the bech32 representation of the address + * Use {@link toBech32} instead. */ bech32(): string { + return this.toBech32(); + } + + /** + * Returns the bech32 representation of the address + */ + toBech32(): string { if (this.isEmpty()) { return ""; } @@ -162,9 +177,16 @@ export class Address { } /** - * Returns the pubkey as raw bytes (buffer) + * Use {@link getPublicKey} instead. */ pubkey(): Buffer { + return this.getPublicKey(); + } + + /** + * Returns the pubkey as raw bytes (buffer) + */ + getPublicKey(): Buffer { if (this.isEmpty()) { return Buffer.from([]); } @@ -172,6 +194,14 @@ export class Address { return Buffer.from(this.valueHex, "hex"); } + /** + * Returns the human-readable-part of the bech32 addresses. + * The HRP is currently hardcoded to "erd". + */ + getHrp(): string { + return HRP; + } + /** * Returns whether the address is empty. */ @@ -194,7 +224,7 @@ export class Address { * Returns the bech32 representation of the address */ toString(): string { - return this.bech32(); + return this.toBech32(); } /** @@ -202,19 +232,30 @@ export class Address { */ toJSON(): object { return { - bech32: this.bech32(), - pubkey: this.hex(), + bech32: this.toBech32(), + pubkey: this.toHex(), }; } /** - * Creates the Zero address (the one that should be used when deploying smart contracts) + * Creates the Zero address (the one that should be used when deploying smart contracts). + * Generally speaking, this should not be used by client code (internal use only). */ static Zero(): Address { return new Address("0".repeat(64)); } + /** + * Use {@link isSmartContract} instead. + */ isContractAddress(): boolean { - return this.hex().startsWith(SMART_CONTRACT_HEX_PUBKEY_PREFIX); + return this.isSmartContract(); + } + + /** + * Returns whether the address is a smart contract address. + */ + isSmartContract(): boolean { + return this.toHex().startsWith(SMART_CONTRACT_HEX_PUBKEY_PREFIX); } } diff --git a/src/compatibility.ts b/src/compatibility.ts index 3aec4764..b214c4f2 100644 --- a/src/compatibility.ts +++ b/src/compatibility.ts @@ -1,26 +1,21 @@ import { Address } from "./address"; +import { Err } from "./errors"; import { IAddress } from "./interface"; /** * For internal use only. */ export class Compatibility { - static areWarningsEnabled: boolean = true; - /** * For internal use only. */ static guardAddressIsSetAndNonZero(address: IAddress | undefined, context: string, resolution: string) { - if (!this.areWarningsEnabled) { - return; - } - if (!address || address.bech32() == "") { - console.warn( + throw new Err( `${context}: address should be set; ${resolution}. In the future, this will throw an exception instead of emitting a WARN.`, ); } else if (address.bech32() == Address.Zero().bech32()) { - console.warn( + throw new Err( `${context}: address should not be the 'zero' address (also known as the 'contracts deployment address'); ${resolution}. In the future, this will throw an exception instead of emitting a WARN.`, ); } diff --git a/src/signableMessage.ts b/src/signableMessage.ts index 9d22e54c..872407cf 100644 --- a/src/signableMessage.ts +++ b/src/signableMessage.ts @@ -37,7 +37,7 @@ export class SignableMessage { this.signature = Buffer.from([]); this.version = 1; this.signer = "ErdJS"; - this.address = new Address(); + this.address = Address.empty(); Object.assign(this, init); } diff --git a/src/smartcontracts/interaction.ts b/src/smartcontracts/interaction.ts index 1b5b71f3..9cf2b7b7 100644 --- a/src/smartcontracts/interaction.ts +++ b/src/smartcontracts/interaction.ts @@ -35,9 +35,9 @@ export class Interaction { private gasLimit: IGasLimit = 0; private gasPrice: IGasPrice | undefined = undefined; private chainID: IChainID = ""; - private querent: IAddress = new Address(); + private querent: IAddress = Address.empty(); private explicitReceiver?: IAddress; - private sender: IAddress = new Address(); + private sender: IAddress = Address.empty(); private isWithSingleESDTTransfer: boolean = false; private isWithSingleESDTNFTTransfer: boolean = false; diff --git a/src/smartcontracts/query.ts b/src/smartcontracts/query.ts index a298ebf0..3db54519 100644 --- a/src/smartcontracts/query.ts +++ b/src/smartcontracts/query.ts @@ -18,7 +18,7 @@ export class Query { args?: TypedValue[], value?: ITransactionValue }) { - this.caller = obj.caller || new Address(); + this.caller = obj.caller || Address.empty(); this.address = obj.address; this.func = obj.func; this.args = obj.args || []; diff --git a/src/smartcontracts/resultsParser.spec.ts b/src/smartcontracts/resultsParser.spec.ts index e257cc07..2c033a65 100644 --- a/src/smartcontracts/resultsParser.spec.ts +++ b/src/smartcontracts/resultsParser.spec.ts @@ -202,7 +202,7 @@ describe("test smart contract results parser", () => { it("should parse contract outcome, on signal error", async () => { let transaction = new TransactionOnNetwork({ logs: new TransactionLogs({ - address: new Address(), + address: Address.empty(), events: [ new TransactionEvent({ identifier: "signalError", @@ -222,7 +222,7 @@ describe("test smart contract results parser", () => { it("should parse contract outcome, on too much gas warning", async () => { let transaction = new TransactionOnNetwork({ logs: new TransactionLogs({ - address: new Address(), + address: Address.empty(), events: [ new TransactionEvent({ identifier: "writeLog", diff --git a/src/smartcontracts/smartContract.ts b/src/smartcontracts/smartContract.ts index 788c9d54..7e02329c 100644 --- a/src/smartcontracts/smartContract.ts +++ b/src/smartcontracts/smartContract.ts @@ -31,7 +31,7 @@ interface IAbi { * An abstraction for deploying and interacting with Smart Contracts. */ export class SmartContract implements ISmartContract { - private address: IAddress = new Address(); + private address: IAddress = Address.empty(); private abi?: IAbi; /** @@ -53,7 +53,7 @@ export class SmartContract implements ISmartContract { * Create a SmartContract object by providing its address on the Network. */ constructor(options: { address?: IAddress, abi?: IAbi } = {}) { - this.address = options.address || new Address(); + this.address = options.address || Address.empty(); this.abi = options.abi; if (this.abi) { diff --git a/src/smartcontracts/transactionPayloadBuilders.ts b/src/smartcontracts/transactionPayloadBuilders.ts index c70fbdcc..4234381f 100644 --- a/src/smartcontracts/transactionPayloadBuilders.ts +++ b/src/smartcontracts/transactionPayloadBuilders.ts @@ -6,11 +6,10 @@ import { TypedValue } from "./typesystem"; export const WasmVirtualMachine = "0500"; -/** - * A builder for {@link TransactionPayload} objects, to be used for Smart Contract deployment transactions. - */ /** * @deprecated Use {@link SmartContractTransactionsFactory} instead. + * + * A builder for {@link TransactionPayload} objects, to be used for Smart Contract deployment transactions. */ export class ContractDeployPayloadBuilder { private code: ICode | null = null; @@ -65,6 +64,8 @@ export class ContractDeployPayloadBuilder { } /** + * @deprecated Use {@link SmartContractTransactionsFactory} instead. + * * A builder for {@link TransactionPayload} objects, to be used for Smart Contract upgrade transactions. */ export class ContractUpgradePayloadBuilder { @@ -120,6 +121,8 @@ export class ContractUpgradePayloadBuilder { } /** + * @deprecated Use {@link SmartContractTransactionsFactory} instead. + * * A builder for {@link TransactionPayload} objects, to be used for Smart Contract execution transactions. */ export class ContractCallPayloadBuilder { diff --git a/src/tokens.spec.ts b/src/tokens.spec.ts index 9fd54cd4..e7949b56 100644 --- a/src/tokens.spec.ts +++ b/src/tokens.spec.ts @@ -1,12 +1,12 @@ -import { Token, TokenComputer } from "./tokens"; import { assert } from "chai"; +import { Token, TokenComputer } from "./tokens"; describe("test token computer", async () => { const tokenComputer = new TokenComputer(); it("should test if token is fungible", async () => { - const fungibleToken = new Token("TEST-123456", 0); - const nonFungibleToken = new Token("NFT-987654", 7); + const fungibleToken = new Token("TEST-123456", 0n); + const nonFungibleToken = new Token("NFT-987654", 7n); assert.equal(tokenComputer.isFungible(fungibleToken), true); assert.equal(tokenComputer.isFungible(nonFungibleToken), false); diff --git a/src/tokens.ts b/src/tokens.ts index e6d18c28..361800ac 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -1,11 +1,10 @@ -import BigNumber from "bignumber.js"; import { ErrInvalidTokenIdentifier } from "./errors"; export class Token { identifier: string; - nonce: BigNumber.Value; + nonce: bigint; - constructor(identifier: string, nonce: BigNumber.Value) { + constructor(identifier: string, nonce: bigint) { this.identifier = identifier; this.nonce = nonce; } @@ -13,9 +12,9 @@ export class Token { export class NextTokenTransfer { token: Token; - amount: BigNumber.Value; + amount: bigint; - constructor(token: Token, amount: BigNumber.Value) { + constructor(token: Token, amount: bigint) { this.token = token; this.amount = amount; } @@ -25,7 +24,7 @@ export class TokenComputer { constructor() {} isFungible(token: Token): boolean { - return token.nonce === 0; + return token.nonce === 0n; } extractNonceFromExtendedIdentifier(identifier: string): number { diff --git a/src/transactionsFactories/smartContractTransactionsFactory.spec.ts b/src/transactionsFactories/smartContractTransactionsFactory.spec.ts index d4ab3c62..fe447a9c 100644 --- a/src/transactionsFactories/smartContractTransactionsFactory.spec.ts +++ b/src/transactionsFactories/smartContractTransactionsFactory.spec.ts @@ -1,15 +1,15 @@ +import BigNumber from "bignumber.js"; import { assert, expect } from "chai"; -import { SmartContractTransactionsFactory } from "./smartContractTransactionsFactory"; import { Address } from "../address"; -import { Code } from "../smartcontracts/code"; -import { AbiRegistry } from "../smartcontracts/typesystem/abiRegistry"; -import { U32Value } from "../smartcontracts"; import { CONTRACT_DEPLOY_ADDRESS } from "../constants"; -import { loadContractCode, loadAbiRegistry } from "../testutils/utils"; import { Err } from "../errors"; +import { U32Value } from "../smartcontracts"; +import { Code } from "../smartcontracts/code"; +import { AbiRegistry } from "../smartcontracts/typesystem/abiRegistry"; +import { loadAbiRegistry, loadContractCode } from "../testutils/utils"; +import { NextTokenTransfer, Token, TokenComputer } from "../tokens"; +import { SmartContractTransactionsFactory } from "./smartContractTransactionsFactory"; import { TransactionsFactoryConfig } from "./transactionsFactoryConfig"; -import BigNumber from "bignumber.js"; -import { Token, NextTokenTransfer, TokenComputer } from "../tokens"; describe("test smart contract transactions factory", function () { const config = new TransactionsFactoryConfig("D"); @@ -149,8 +149,8 @@ describe("test smart contract transactions factory", function () { const func = "add"; const gasLimit = 6000000; const args = [new U32Value(7)]; - const token = new Token("FOO-6ce17b", 0); - const transfer = new NextTokenTransfer(token, 10); + const token = new Token("FOO-6ce17b", 0n); + const transfer = new NextTokenTransfer(token, 10n); const transaction = smartContractFactory.createTransactionForExecute({ sender: sender, @@ -185,10 +185,10 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000; const args = [new U32Value(7)]; - const fooToken = new Token("FOO-6ce17b", 0); - const fooTransfer = new NextTokenTransfer(fooToken, 10); - const barToken = new Token("BAR-5bc08f", 0); - const barTransfer = new NextTokenTransfer(barToken, 3140); + const fooToken = new Token("FOO-6ce17b", 0n); + const fooTransfer = new NextTokenTransfer(fooToken, 10n); + const barToken = new Token("BAR-5bc08f", 0n); + const barTransfer = new NextTokenTransfer(barToken, 3140n); const transaction = smartContractFactory.createTransactionForExecute({ sender: sender, @@ -230,8 +230,8 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000; const args = [new U32Value(7)]; - const token = new Token("NFT-123456", 1); - const transfer = new NextTokenTransfer(token, 1); + const token = new Token("NFT-123456", 1n); + const transfer = new NextTokenTransfer(token, 1n); const transaction = smartContractFactory.createTransactionForExecute({ sender: sender, @@ -274,10 +274,10 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000; const args = [new U32Value(7)]; - const firstToken = new Token("NFT-123456", 1); - const firstTransfer = new NextTokenTransfer(firstToken, 1); - const secondToken = new Token("NFT-123456", 42); - const secondTransfer = new NextTokenTransfer(secondToken, 1); + const firstToken = new Token("NFT-123456", 1n); + const firstTransfer = new NextTokenTransfer(firstToken, 1n); + const secondToken = new Token("NFT-123456", 42n); + const secondTransfer = new NextTokenTransfer(secondToken, 1n); const transaction = smartContractFactory.createTransactionForExecute({ sender: sender, diff --git a/src/transactionsFactories/tokenTransfersDataBuilder.ts b/src/transactionsFactories/tokenTransfersDataBuilder.ts index 7804e7bd..593f9275 100644 --- a/src/transactionsFactories/tokenTransfersDataBuilder.ts +++ b/src/transactionsFactories/tokenTransfersDataBuilder.ts @@ -1,6 +1,6 @@ import { IAddress } from "../interface"; import { NextTokenTransfer, TokenComputer } from "../tokens"; -import { numberToPaddedHex, utf8ToHex, addressToHex } from "../utils.codec"; +import { addressToHex, numberToPaddedHex, utf8ToHex } from "../utils.codec"; export class TokenTransfersDataBuilder { private tokenComputer: TokenComputer; diff --git a/src/transactionsFactories/transferTransactionsFactory.spec.ts b/src/transactionsFactories/transferTransactionsFactory.spec.ts index 2f609159..39903b91 100644 --- a/src/transactionsFactories/transferTransactionsFactory.spec.ts +++ b/src/transactionsFactories/transferTransactionsFactory.spec.ts @@ -1,9 +1,9 @@ import { assert } from "chai"; import { Address } from "../address"; -import { Token, NextTokenTransfer, TokenComputer } from "../tokens"; +import { ErrBadUsage } from "../errors"; +import { NextTokenTransfer, Token, TokenComputer } from "../tokens"; import { TransactionsFactoryConfig } from "./transactionsFactoryConfig"; import { NextTransferTransactionsFactory } from "./transferTransactionsFactory"; -import { ErrBadUsage } from "../errors"; describe("test transfer transcations factory", function () { const config = new TransactionsFactoryConfig("D"); @@ -58,8 +58,8 @@ describe("test transfer transcations factory", function () { }); it("should create 'TransactionNext' for esdt transfer", async () => { - const fooToken = new Token("FOO-123456", 0); - const transfer = new NextTokenTransfer(fooToken, 1000000); + const fooToken = new Token("FOO-123456", 0n); + const transfer = new NextTokenTransfer(fooToken, 1000000n); const transaction = nextTransferFactory.createTransactionForESDTTokenTransfer({ sender: alice, @@ -75,8 +75,8 @@ describe("test transfer transcations factory", function () { }); it("should create 'TransactionNext' for nft transfer", async () => { - const nft = new Token("NFT-123456", 10); - const transfer = new NextTokenTransfer(nft, 1); + const nft = new Token("NFT-123456", 10n); + const transfer = new NextTokenTransfer(nft, 1n); const transaction = nextTransferFactory.createTransactionForESDTTokenTransfer({ sender: alice, @@ -95,11 +95,11 @@ describe("test transfer transcations factory", function () { }); it("should create 'TransactionNext' for multiple nft transfers", async () => { - const firstNft = new Token("NFT-123456", 10); - const firstTransfer = new NextTokenTransfer(firstNft, 1); + const firstNft = new Token("NFT-123456", 10n); + const firstTransfer = new NextTokenTransfer(firstNft, 1n); - const secondNft = new Token("TEST-987654", 1); - const secondTransfer = new NextTokenTransfer(secondNft, 1); + const secondNft = new Token("TEST-987654", 1n); + const secondTransfer = new NextTokenTransfer(secondNft, 1n); const transaction = nextTransferFactory.createTransactionForESDTTokenTransfer({ sender: alice, diff --git a/src/utils.codec.spec.ts b/src/utils.codec.spec.ts index ba38f632..817496cc 100644 --- a/src/utils.codec.spec.ts +++ b/src/utils.codec.spec.ts @@ -1,11 +1,19 @@ import { assert } from "chai"; -import { isPaddedHex, numberToPaddedHex, zeroPadStringIfOddLength, byteArrayToHex, utf8ToHex } from "./utils.codec"; +import { byteArrayToHex, isPaddedHex, numberToPaddedHex, utf8ToHex, zeroPadStringIfOddLength } from "./utils.codec"; describe("test codec utils", () => { it("should convert numberToPaddedHex", () => { assert.equal(numberToPaddedHex(1), "01"); assert.equal(numberToPaddedHex(10), "0a"); assert.equal(numberToPaddedHex(256), "0100"); + + assert.equal(numberToPaddedHex(1n), "01"); + assert.equal(numberToPaddedHex(10n), "0a"); + assert.equal(numberToPaddedHex(256n), "0100"); + + assert.equal(numberToPaddedHex("1"), "01"); + assert.equal(numberToPaddedHex("10"), "0a"); + assert.equal(numberToPaddedHex("256"), "0100"); }); it("should check if isPaddedHex", () => { diff --git a/src/utils.codec.ts b/src/utils.codec.ts index 6d326412..0e03b658 100644 --- a/src/utils.codec.ts +++ b/src/utils.codec.ts @@ -1,10 +1,18 @@ import BigNumber from "bignumber.js"; -import * as contractsCodecUtils from "./smartcontracts/codec/utils"; import { Address } from "./address"; import { IAddress } from "./interface"; +import * as contractsCodecUtils from "./smartcontracts/codec/utils"; + +export function numberToPaddedHex(value: bigint | number | BigNumber.Value) { + let hexableNumber: { toString(radix?: number): string }; + + if (typeof value === "bigint" || typeof value === "number") { + hexableNumber = value; + } else { + hexableNumber = new BigNumber(value); + } -export function numberToPaddedHex(value: BigNumber.Value) { - let hex = new BigNumber(value).toString(16); + const hex = hexableNumber.toString(16); return zeroPadStringIfOddLength(hex); } diff --git a/tsconfig.json b/tsconfig.json index 716261e6..089ef306 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,10 @@ { "compilerOptions": { "module": "CommonJS", - "target": "es2015", + "target": "ES2020", "outDir": "out", "lib": [ - "ES2015", + "ES2020", "DOM" ], "sourceMap": true, diff --git a/tsconfig.tests.json b/tsconfig.tests.json index 29ec228e..52a987db 100644 --- a/tsconfig.tests.json +++ b/tsconfig.tests.json @@ -1,10 +1,10 @@ { "compilerOptions": { "module": "CommonJS", - "target": "ES2015", + "target": "ES2020", "outDir": "out-tests", "lib": [ - "ES2015", + "ES2020", "DOM" ], "sourceMap": true,