diff --git a/token/js/.mocharc.json b/token/js/.mocharc.json index 65146859..5eb37ee8 100644 --- a/token/js/.mocharc.json +++ b/token/js/.mocharc.json @@ -1,5 +1,4 @@ { "extension": ["ts"], - "node-option": ["experimental-specifier-resolution=node", "loader=ts-node/esm"], - "spec": ["test/**/*.test.ts"] + "node-option": ["experimental-specifier-resolution=node", "loader=ts-node/esm"] } diff --git a/token/js/.prettierignore b/token/js/.prettierignore index c3997f2c..a81d45c2 100644 --- a/token/js/.prettierignore +++ b/token/js/.prettierignore @@ -1,3 +1,3 @@ docs lib - +test-ledger diff --git a/token/js/package.json b/token/js/package.json index b7356e4d..ad50d5c8 100644 --- a/token/js/package.json +++ b/token/js/package.json @@ -31,7 +31,10 @@ "postbuild": "echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json && echo '{\"type\":\"module\"}' > lib/esm/package.json", "deploy": "yarn docs && gh-pages --dist docs --dotfiles", "example": "node --experimental-specifier-resolution=node --loader ts-node/esm examples/create_mint_and_transfer_tokens.ts", - "test": "mocha", + "test": "yarn test:unit && yarn test:e2e-built && yarn test:e2e-native", + "test:unit": "mocha test/unit", + "test:e2e-built": "start-server-and-test 'solana-test-validator --bpf-program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA ../../target/deploy/spl_token.so --reset --quiet' http://localhost:8899/health 'mocha test/e2e'", + "test:e2e-native": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health 'mocha test/e2e'", "docs": "shx rm -rf docs && NODE_OPTIONS=--max_old_space_size=4096 typedoc && shx cp .nojekyll docs/", "fmt": "prettier --write '{*,**/*}.{js,ts,jsx,tsx,json}'", "lint": "eslint --ext .ts . && prettier --check '{*,**/*}.{js,ts,jsx,tsx,json}'", @@ -41,7 +44,8 @@ "dependencies": { "@solana/buffer-layout": "^4.0.0", "@solana/buffer-layout-utils": "^0.2.0", - "@solana/web3.js": "^1.32.0" + "@solana/web3.js": "^1.32.0", + "start-server-and-test": "^1.14.0" }, "devDependencies": { "@types/chai-as-promised": "^7.1.4", diff --git a/token/js/test/e2e/burn.test.ts b/token/js/test/e2e/burn.test.ts new file mode 100644 index 00000000..78023e88 --- /dev/null +++ b/token/js/test/e2e/burn.test.ts @@ -0,0 +1,65 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { TOKEN_PROGRAM_ID, createMint, createAccount, getAccount, mintTo, burn, burnChecked } from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('burn', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let owner: Keypair; + let account: PublicKey; + let amount: bigint; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }); + beforeEach(async () => { + owner = Keypair.generate(); + account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TOKEN_PROGRAM_ID); + amount = BigInt(1000); + await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TOKEN_PROGRAM_ID); + }); + it('burn', async () => { + const burnAmount = BigInt(1); + await burn(connection, payer, account, mint, owner, burnAmount, [], undefined, TOKEN_PROGRAM_ID); + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.amount).to.eql(amount - burnAmount); + }); + it('burnChecked', async () => { + const burnAmount = BigInt(1); + await burnChecked( + connection, + payer, + account, + mint, + owner, + burnAmount, + TEST_TOKEN_DECIMALS, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.amount).to.eql(amount - burnAmount); + }); +}); diff --git a/token/js/test/e2e/close.test.ts b/token/js/test/e2e/close.test.ts new file mode 100644 index 00000000..4459b4c5 --- /dev/null +++ b/token/js/test/e2e/close.test.ts @@ -0,0 +1,68 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { TOKEN_PROGRAM_ID, createMint, createAccount, closeAccount, mintTo } from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('freezeThaw', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let freezeAuthority: Keypair; + let owner: Keypair; + let account: PublicKey; + let destination: PublicKey; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + freezeAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + freezeAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }); + beforeEach(async () => { + owner = Keypair.generate(); + destination = Keypair.generate().publicKey; + account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TOKEN_PROGRAM_ID); + }); + it('failsWithNonZeroAmount', async () => { + const amount = BigInt(1000); + await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TOKEN_PROGRAM_ID); + expect(closeAccount(connection, payer, account, destination, owner, [], undefined, TOKEN_PROGRAM_ID)).to.be + .rejected; + }); + it('works', async () => { + const accountInfo = await connection.getAccountInfo(account); + let tokenRentExemptAmount; + expect(accountInfo).to.not.be.null; + if (accountInfo !== null) { + tokenRentExemptAmount = accountInfo.lamports; + } + + await closeAccount(connection, payer, account, destination, owner, [], undefined, TOKEN_PROGRAM_ID); + + const closedInfo = await connection.getAccountInfo(account); + expect(closedInfo).to.be.null; + + const destinationInfo = await connection.getAccountInfo(destination); + expect(destinationInfo).to.not.be.null; + if (destinationInfo !== null) { + expect(destinationInfo.lamports).to.eql(tokenRentExemptAmount); + } + }); +}); diff --git a/token/js/test/e2e/common.ts b/token/js/test/e2e/common.ts new file mode 100644 index 00000000..8e5d8a6a --- /dev/null +++ b/token/js/test/e2e/common.ts @@ -0,0 +1,15 @@ +import { Keypair, Connection, Signer } from '@solana/web3.js'; + +export async function newAccountWithLamports(connection: Connection, lamports = 1000000): Promise { + const account = Keypair.generate(); + const signature = await connection.requestAirdrop(account.publicKey, lamports); + await connection.confirmTransaction(signature); + return account; +} + +export async function getConnection(): Promise { + const url = 'http://localhost:8899'; + const connection = new Connection(url, 'confirmed'); + await connection.getVersion(); + return connection; +} diff --git a/token/js/test/e2e/create.test.ts b/token/js/test/e2e/create.test.ts new file mode 100644 index 00000000..2f447e28 --- /dev/null +++ b/token/js/test/e2e/create.test.ts @@ -0,0 +1,146 @@ +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, + createMint, + getMint, + createAccount, + getAccount, + getAssociatedTokenAddress, +} from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('createMint', () => { + it('works', async () => { + const connection = await getConnection(); + const payer = await newAccountWithLamports(connection, 1000000000); + const testMintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + const mint = await createMint( + connection, + payer, + testMintAuthority.publicKey, + testMintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + + const mintInfo = await getMint(connection, mint, undefined, TOKEN_PROGRAM_ID); + + expect(mintInfo.mintAuthority).to.eql(testMintAuthority.publicKey); + expect(mintInfo.supply).to.eql(BigInt(0)); + expect(mintInfo.decimals).to.eql(TEST_TOKEN_DECIMALS); + expect(mintInfo.isInitialized).to.be.true; + expect(mintInfo.freezeAuthority).to.eql(testMintAuthority.publicKey); + }); +}); + +describe('createAccount', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + const mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }), + it('auxiliary token account', async () => { + const owner = Keypair.generate(); + const account = await createAccount( + connection, + payer, + mint, + owner.publicKey, + Keypair.generate(), + undefined, + TOKEN_PROGRAM_ID + ); + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.mint).to.eql(mint); + expect(accountInfo.owner).to.eql(owner.publicKey); + expect(accountInfo.amount).to.eql(BigInt(0)); + expect(accountInfo.delegate).to.be.null; + expect(accountInfo.delegatedAmount).to.eql(BigInt(0)); + expect(accountInfo.isInitialized).to.be.true; + expect(accountInfo.isFrozen).to.be.false; + expect(accountInfo.isNative).to.be.false; + expect(accountInfo.rentExemptReserve).to.be.null; + expect(accountInfo.closeAuthority).to.be.null; + + // you can create as many accounts as with same owner + const account2 = await createAccount( + connection, + payer, + mint, + owner.publicKey, + Keypair.generate(), + undefined, + TOKEN_PROGRAM_ID + ); + expect(account2).to.not.eql(account); + }), + it('associated token account', async () => { + const owner = Keypair.generate(); + const associatedAddress = await getAssociatedTokenAddress( + mint, + owner.publicKey, + false, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID + ); + + // associated account shouldn't exist + const info = await connection.getAccountInfo(associatedAddress); + expect(info).to.be.null; + + const createdAddress = await createAccount( + connection, + payer, + mint, + owner.publicKey, + undefined, // uses ATA by default + undefined, + TOKEN_PROGRAM_ID + ); + expect(createdAddress).to.eql(associatedAddress); + + const accountInfo = await getAccount(connection, associatedAddress, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo).to.not.be.null; + expect(accountInfo.mint).to.eql(mint); + expect(accountInfo.owner).to.eql(owner.publicKey); + expect(accountInfo.amount).to.eql(BigInt(0)); + + // creating again should cause TX error for the associated token account + expect( + createAccount( + connection, + payer, + mint, + owner.publicKey, + undefined, // uses ATA by default + undefined, + TOKEN_PROGRAM_ID + ) + ).to.be.rejected; + }); +}); diff --git a/token/js/test/e2e/freeze.test.ts b/token/js/test/e2e/freeze.test.ts new file mode 100644 index 00000000..58e5b061 --- /dev/null +++ b/token/js/test/e2e/freeze.test.ts @@ -0,0 +1,70 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { + TOKEN_PROGRAM_ID, + burn, + createMint, + createAccount, + getAccount, + freezeAccount, + thawAccount, + mintTo, +} from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('freezeThaw', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let freezeAuthority: Keypair; + let owner: Keypair; + let account: PublicKey; + let amount: bigint; + const burnAmount = BigInt(1); + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + freezeAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + freezeAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }); + beforeEach(async () => { + owner = Keypair.generate(); + account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TOKEN_PROGRAM_ID); + amount = BigInt(1000); + await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TOKEN_PROGRAM_ID); + }); + it('freezes', async () => { + await freezeAccount(connection, payer, account, mint, freezeAuthority, [], undefined, TOKEN_PROGRAM_ID); + + expect(burn(connection, payer, account, mint, owner, burnAmount, [], undefined, TOKEN_PROGRAM_ID)).to.be + .rejected; + }); + it('thaws', async () => { + await freezeAccount(connection, payer, account, mint, freezeAuthority, [], undefined, TOKEN_PROGRAM_ID); + + await thawAccount(connection, payer, account, mint, freezeAuthority, [], undefined, TOKEN_PROGRAM_ID); + + await burn(connection, payer, account, mint, owner, burnAmount, [], undefined, TOKEN_PROGRAM_ID); + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + + expect(accountInfo.amount).to.eql(amount - burnAmount); + }); +}); diff --git a/token/js/test/e2e/mint.test.ts b/token/js/test/e2e/mint.test.ts new file mode 100644 index 00000000..6e8741b9 --- /dev/null +++ b/token/js/test/e2e/mint.test.ts @@ -0,0 +1,66 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { TOKEN_PROGRAM_ID, createMint, getMint, createAccount, getAccount, mintTo, mintToChecked } from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('mint', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let owner: Keypair; + let account: PublicKey; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + owner = Keypair.generate(); + account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TOKEN_PROGRAM_ID); + }); + it('mintTo', async () => { + const amount = BigInt(1000); + await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TOKEN_PROGRAM_ID); + + const mintInfo = await getMint(connection, mint, undefined, TOKEN_PROGRAM_ID); + expect(mintInfo.supply).to.eql(amount); + + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.amount).to.eql(amount); + }); + it('mintToChecked', async () => { + const amount = BigInt(1000); + await mintToChecked( + connection, + payer, + mint, + account, + mintAuthority, + amount, + TEST_TOKEN_DECIMALS, + [], + undefined, + TOKEN_PROGRAM_ID + ); + + expect( + mintToChecked(connection, payer, mint, account, mintAuthority, amount, 1, [], undefined, TOKEN_PROGRAM_ID) + ).to.be.rejected; + }); +}); diff --git a/token/js/test/e2e/multisig.test.ts b/token/js/test/e2e/multisig.test.ts new file mode 100644 index 00000000..f95bcb1d --- /dev/null +++ b/token/js/test/e2e/multisig.test.ts @@ -0,0 +1,113 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { + TOKEN_PROGRAM_ID, + AuthorityType, + createMint, + createAccount, + getAccount, + mintTo, + transfer, + approve, + getMultisig, + createMultisig, + setAuthority, +} from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +const M = 2; +const N = 5; +describe('multisig', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let account1: PublicKey; + let account2: PublicKey; + let amount: bigint; + let multisig: PublicKey; + let signers: Keypair[]; + let signerPublicKeys: PublicKey[]; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + signers = []; + signerPublicKeys = []; + for (let i = 0; i < N; ++i) { + const signer = Keypair.generate(); + signers.push(signer); + signerPublicKeys.push(signer.publicKey); + } + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }); + beforeEach(async () => { + multisig = await createMultisig(connection, payer, signerPublicKeys, M, undefined, undefined, TOKEN_PROGRAM_ID); + account1 = await createAccount(connection, payer, mint, multisig, undefined, undefined, TOKEN_PROGRAM_ID); + account2 = await createAccount( + connection, + payer, + mint, + multisig, + Keypair.generate(), + undefined, + TOKEN_PROGRAM_ID + ); + amount = BigInt(1000); + await mintTo(connection, payer, mint, account1, mintAuthority, amount, [], undefined, TOKEN_PROGRAM_ID); + }); + it('create', async () => { + const multisigInfo = await getMultisig(connection, multisig, undefined, TOKEN_PROGRAM_ID); + expect(multisigInfo.m).to.eql(M); + expect(multisigInfo.n).to.eql(N); + expect(multisigInfo.signer1).to.eql(signerPublicKeys[0]); + expect(multisigInfo.signer2).to.eql(signerPublicKeys[1]); + expect(multisigInfo.signer3).to.eql(signerPublicKeys[2]); + expect(multisigInfo.signer4).to.eql(signerPublicKeys[3]); + expect(multisigInfo.signer5).to.eql(signerPublicKeys[4]); + }); + it('transfer', async () => { + await transfer(connection, payer, account1, account2, multisig, amount, signers, undefined, TOKEN_PROGRAM_ID); + const accountInfo = await getAccount(connection, account2, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.amount).to.eql(amount); + }); + it('approve', async () => { + const delegate = Keypair.generate().publicKey; + await approve(connection, payer, account1, delegate, multisig, amount, signers, undefined, TOKEN_PROGRAM_ID); + const approvedAccountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(approvedAccountInfo.delegatedAmount).to.eql(amount); + expect(approvedAccountInfo.delegate).to.eql(delegate); + }); + it('setAuthority', async () => { + const newOwner = Keypair.generate().publicKey; + await setAuthority( + connection, + payer, + account1, + multisig, + AuthorityType.AccountOwner, + newOwner, + signers, + undefined, + TOKEN_PROGRAM_ID + ); + const accountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.owner).to.eql(newOwner); + }); +}); diff --git a/token/js/test/e2e/native.test.ts b/token/js/test/e2e/native.test.ts new file mode 100644 index 00000000..fa27c021 --- /dev/null +++ b/token/js/test/e2e/native.test.ts @@ -0,0 +1,104 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { + Connection, + Keypair, + PublicKey, + Signer, + Transaction, + SystemProgram, + sendAndConfirmTransaction, +} from '@solana/web3.js'; + +import { TOKEN_PROGRAM_ID, closeAccount, getAccount, createWrappedNativeAccount, syncNative } from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +describe('native', () => { + let connection: Connection; + let payer: Signer; + let owner: Keypair; + let account: PublicKey; + let amount: number; + before(async () => { + amount = 1_000_000_000; + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 100_000_000_000); + }); + beforeEach(async () => { + owner = Keypair.generate(); + account = await createWrappedNativeAccount( + connection, + payer, + owner.publicKey, + amount, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + }); + it('works', async () => { + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.isNative).to.be.true; + expect(accountInfo.amount).to.eql(BigInt(amount)); + }); + it('syncNative', async () => { + let balance = 0; + const preInfo = await connection.getAccountInfo(account); + expect(preInfo).to.not.be.null; + if (preInfo != null) { + balance = preInfo.lamports; + } + + // transfer lamports into the native account + const additionalLamports = 100; + await sendAndConfirmTransaction( + connection, + new Transaction().add( + SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: account, + lamports: additionalLamports, + }) + ), + [payer] + ); + + // no change in the amount + const preAccountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(preAccountInfo.isNative).to.be.true; + expect(preAccountInfo.amount).to.eql(BigInt(amount)); + + // but change in lamports + const postInfo = await connection.getAccountInfo(account); + expect(postInfo).to.not.be.null; + if (postInfo !== null) { + expect(postInfo.lamports).to.eql(balance + additionalLamports); + } + + // sync, amount changes + await syncNative(connection, payer, account, undefined, TOKEN_PROGRAM_ID); + const postAccountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(postAccountInfo.isNative).to.be.true; + expect(postAccountInfo.amount).to.eql(BigInt(amount + additionalLamports)); + }); + it('closeAccount', async () => { + let balance = 0; + const preInfo = await connection.getAccountInfo(account); + expect(preInfo).to.not.be.null; + if (preInfo != null) { + balance = preInfo.lamports; + } + const destination = Keypair.generate().publicKey; + await closeAccount(connection, payer, account, destination, owner, [], undefined, TOKEN_PROGRAM_ID); + const nullInfo = await connection.getAccountInfo(account); + expect(nullInfo).to.be.null; + const destinationInfo = await connection.getAccountInfo(destination); + expect(destinationInfo).to.not.be.null; + if (destinationInfo != null) { + expect(destinationInfo.lamports).to.eql(balance); + } + }); +}); diff --git a/token/js/test/e2e/setAuthority.test.ts b/token/js/test/e2e/setAuthority.test.ts new file mode 100644 index 00000000..9a753338 --- /dev/null +++ b/token/js/test/e2e/setAuthority.test.ts @@ -0,0 +1,118 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { + TOKEN_PROGRAM_ID, + AuthorityType, + createMint, + createAccount, + getAccount, + getMint, + setAuthority, +} from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('setAuthority', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let owner: Keypair; + let account: PublicKey; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }); + beforeEach(async () => { + owner = Keypair.generate(); + account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TOKEN_PROGRAM_ID); + }); + it('AccountOwner', async () => { + const newOwner = Keypair.generate(); + await setAuthority( + connection, + payer, + account, + owner, + AuthorityType.AccountOwner, + newOwner.publicKey, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.owner).to.eql(newOwner.publicKey); + await setAuthority( + connection, + payer, + account, + newOwner, + AuthorityType.AccountOwner, + owner.publicKey, + [], + undefined, + TOKEN_PROGRAM_ID + ); + expect( + setAuthority( + connection, + payer, + account, + newOwner, + AuthorityType.AccountOwner, + owner.publicKey, + [], + undefined, + TOKEN_PROGRAM_ID + ) + ).to.be.rejected; + }); + it('MintAuthority', async () => { + await setAuthority( + connection, + payer, + mint, + mintAuthority, + AuthorityType.MintTokens, + null, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const mintInfo = await getMint(connection, mint, undefined, TOKEN_PROGRAM_ID); + expect(mintInfo.mintAuthority).to.be.null; + }); + it('CloseAuthority', async () => { + const closeAuthority = Keypair.generate(); + await setAuthority( + connection, + payer, + account, + owner, + AuthorityType.CloseAccount, + closeAuthority.publicKey, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const accountInfo = await getAccount(connection, account, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.closeAuthority).to.eql(closeAuthority.publicKey); + }); +}); diff --git a/token/js/test/e2e/transfer.test.ts b/token/js/test/e2e/transfer.test.ts new file mode 100644 index 00000000..1a3aab11 --- /dev/null +++ b/token/js/test/e2e/transfer.test.ts @@ -0,0 +1,175 @@ +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; + +import { + TOKEN_PROGRAM_ID, + createMint, + createAccount, + getAccount, + mintTo, + transfer, + transferChecked, + approve, + approveChecked, + revoke, +} from '../../src'; + +import { newAccountWithLamports, getConnection } from './common'; + +const TEST_TOKEN_DECIMALS = 2; +describe('transfer', () => { + let connection: Connection; + let payer: Signer; + let mint: PublicKey; + let mintAuthority: Keypair; + let owner1: Keypair; + let account1: PublicKey; + let owner2: Keypair; + let account2: PublicKey; + let amount: bigint; + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TOKEN_PROGRAM_ID + ); + }); + beforeEach(async () => { + owner1 = Keypair.generate(); + account1 = await createAccount( + connection, + payer, + mint, + owner1.publicKey, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + owner2 = Keypair.generate(); + account2 = await createAccount( + connection, + payer, + mint, + owner2.publicKey, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + amount = BigInt(1000); + await mintTo(connection, payer, mint, account1, mintAuthority, amount, [], undefined, TOKEN_PROGRAM_ID); + }); + it('transfer', async () => { + await transfer(connection, payer, account1, account2, owner1, amount, [], undefined, TOKEN_PROGRAM_ID); + + const destAccountInfo = await getAccount(connection, account2, undefined, TOKEN_PROGRAM_ID); + expect(destAccountInfo.amount).to.eql(amount); + + const sourceAccountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(sourceAccountInfo.amount).to.eql(BigInt(0)); + }); + it('transferChecked', async () => { + const transferAmount = amount / BigInt(2); + await transferChecked( + connection, + payer, + account1, + mint, + account2, + owner1, + transferAmount, + TEST_TOKEN_DECIMALS, + [], + undefined, + TOKEN_PROGRAM_ID + ); + + const destAccountInfo = await getAccount(connection, account2, undefined, TOKEN_PROGRAM_ID); + expect(destAccountInfo.amount).to.eql(transferAmount); + + const sourceAccountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(sourceAccountInfo.amount).to.eql(transferAmount); + expect( + transferChecked( + connection, + payer, + account1, + mint, + account2, + owner1, + transferAmount, + TEST_TOKEN_DECIMALS - 1, + [], + undefined, + TOKEN_PROGRAM_ID + ) + ).to.be.rejected; + }); + it('approveRevoke', async () => { + const delegate = Keypair.generate(); + const delegatedAmount = amount / BigInt(2); + await approve( + connection, + payer, + account1, + delegate.publicKey, + owner1, + delegatedAmount, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const approvedAccountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(approvedAccountInfo.delegatedAmount).to.eql(delegatedAmount); + expect(approvedAccountInfo.delegate).to.eql(delegate.publicKey); + await revoke(connection, payer, account1, owner1, [], undefined, TOKEN_PROGRAM_ID); + const revokedAccountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(revokedAccountInfo.delegatedAmount).to.eql(BigInt(0)); + expect(revokedAccountInfo.delegate).to.be.null; + }); + it('delegateTransfer', async () => { + const delegate = Keypair.generate(); + const delegatedAmount = amount / BigInt(2); + await approveChecked( + connection, + payer, + mint, + account1, + delegate.publicKey, + owner1, + delegatedAmount, + TEST_TOKEN_DECIMALS, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const transferAmount = delegatedAmount - BigInt(1); + await transfer( + connection, + payer, + account1, + account2, + delegate, + transferAmount, + [], + undefined, + TOKEN_PROGRAM_ID + ); + const accountInfo = await getAccount(connection, account1, undefined, TOKEN_PROGRAM_ID); + expect(accountInfo.delegatedAmount).to.eql(delegatedAmount - transferAmount); + expect(accountInfo.delegate).to.eql(delegate.publicKey); + expect(transfer(connection, payer, account1, account2, delegate, BigInt(2), [], undefined, TOKEN_PROGRAM_ID)).to + .be.rejected; + }); +}); diff --git a/token/js/test/index.test.ts b/token/js/test/unit/index.test.ts similarity index 99% rename from token/js/test/index.test.ts rename to token/js/test/unit/index.test.ts index dad713d8..c8abaec6 100644 --- a/token/js/test/index.test.ts +++ b/token/js/test/unit/index.test.ts @@ -10,7 +10,7 @@ import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID, TokenOwnerOffCurveError, -} from '../src'; +} from '../../src'; chai.use(chaiAsPromised); diff --git a/token/js/yarn.lock b/token/js/yarn.lock index f9562310..22955278 100644 --- a/token/js/yarn.lock +++ b/token/js/yarn.lock @@ -57,6 +57,18 @@ "@ethersproject/logger" "^5.5.0" hash.js "1.1.7" +"@hapi/hoek@^9.0.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" + integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + "@humanwhocodes/config-array@^0.9.2": version "0.9.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" @@ -97,6 +109,23 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@sideway/address@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" + integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@solana/buffer-layout-utils@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" @@ -466,6 +495,13 @@ async@^2.6.1: dependencies: lodash "^4.17.14" +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -507,6 +543,11 @@ bindings@^1.3.0: dependencies: file-uri-to-path "1.0.0" +bluebird@3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" @@ -632,6 +673,11 @@ check-error@^1.0.2: resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +check-more-types@2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= + chokidar@3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -700,7 +746,7 @@ cross-fetch@^3.1.4: dependencies: node-fetch "2.6.7" -cross-spawn@^7.0.2: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -776,6 +822,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +duplexer@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -1004,11 +1055,39 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-stream@=3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +execa@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + eyes@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" @@ -1140,6 +1219,16 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== +follow-redirects@^1.14.0: + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== + +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -1188,6 +1277,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -1338,6 +1432,11 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -1504,6 +1603,11 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -1579,6 +1683,17 @@ jayson@^3.4.4: uuid "^8.3.2" ws "^7.4.5" +joi@^17.4.0: + version "17.6.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" + integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + js-sha3@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" @@ -1623,6 +1738,11 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +lazy-ass@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1650,7 +1770,7 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.14, lodash@^4.17.20: +lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1694,11 +1814,21 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= + marked@^4.0.10: version "4.0.10" resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.10.tgz#423e295385cc0c3a70fa495e0df68b007b879423" integrity sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -1712,6 +1842,11 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -1729,7 +1864,7 @@ minimatch@3.0.4, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.3: +minimist@^1.2.3, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -1811,6 +1946,13 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -1843,6 +1985,13 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -1905,7 +2054,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -1925,6 +2074,13 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= + dependencies: + through "~2.3" + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -1983,6 +2139,13 @@ promise.allsettled@1.0.4: get-intrinsic "^1.0.2" iterate-value "^1.0.2" +ps-tree@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" + integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== + dependencies: + event-stream "=3.3.4" + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -2076,6 +2239,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^7.1.0: + version "7.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" + integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== + dependencies: + tslib "^2.1.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -2156,6 +2326,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -2166,6 +2341,33 @@ sourcemap-codec@^1.4.4: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= + dependencies: + through "2" + +start-server-and-test@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" + integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== + dependencies: + bluebird "3.7.2" + check-more-types "2.24.0" + debug "4.3.2" + execa "5.1.1" + lazy-ass "1.6.0" + ps-tree "1.2.0" + wait-on "6.0.0" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= + dependencies: + duplexer "~0.1.1" + string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -2198,6 +2400,11 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2244,7 +2451,7 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -"through@>=2.2.7 <3": +through@2, "through@>=2.2.7 <3", through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -2291,7 +2498,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.3.1: +tslib@^2.1.0, tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -2408,6 +2615,17 @@ vscode-textmate@5.2.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== +wait-on@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.0.tgz#7e9bf8e3d7fe2daecbb7a570ac8ca41e9311c7e7" + integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== + dependencies: + axios "^0.21.1" + joi "^17.4.0" + lodash "^4.17.21" + minimist "^1.2.5" + rxjs "^7.1.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"