solana/web3.js/test/token-program.test.js

610 lines
14 KiB
JavaScript
Raw Normal View History

2018-10-06 11:23:18 -07:00
// @flow
2018-11-04 11:41:21 -08:00
import {Connection, PublicKey, Token, TokenAmount} from '../src';
import {SYSTEM_TOKEN_PROGRAM_ID} from '../src/token-program';
2018-10-06 11:23:18 -07:00
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
import {url} from './url';
2019-03-05 17:52:13 -08:00
import {newAccountWithLamports} from './new-account-with-lamports';
2019-03-04 08:06:33 -08:00
import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
2018-11-16 19:29:14 -08:00
import {sleep} from '../src/util/sleep';
2018-10-06 11:23:18 -07:00
// The default of 5 seconds is too slow for live testing sometimes
jest.setTimeout(60000);
2018-10-06 11:23:18 -07:00
2019-04-10 14:40:49 -07:00
function mockGetSignatureStatus(result: Object = {Ok: null}) {
2018-10-06 11:23:18 -07:00
mockRpc.push([
url,
{
method: 'getSignatureStatus',
},
{
error: null,
result,
},
]);
}
function mockSendTransaction() {
mockRpc.push([
url,
{
method: 'sendTransaction',
},
{
error: null,
2018-11-04 11:41:21 -08:00
result:
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
},
2018-10-06 11:23:18 -07:00
]);
}
// A token created by the first test and used by all subsequent tests
let testToken: Token;
// Initial owner of the token supply
let initialOwner;
let initialOwnerTokenAccount: PublicKey;
test('create new token', async () => {
const connection = new Connection(url);
2019-03-04 08:06:33 -08:00
connection._disableBlockhashCaching = mockRpcEnabled;
2018-10-06 11:23:18 -07:00
2019-03-05 17:52:13 -08:00
initialOwner = await newAccountWithLamports(connection, 1024);
2018-10-06 11:23:18 -07:00
{
// mock SystemProgram.createAccount transaction for Token.createNewToken()
2019-03-04 08:06:33 -08:00
mockGetRecentBlockhash();
2018-10-06 11:23:18 -07:00
mockSendTransaction();
mockGetSignatureStatus();
// mock Token.newAccount() transaction
mockSendTransaction();
2019-04-10 14:40:49 -07:00
mockGetSignatureStatus(null);
2018-10-06 11:23:18 -07:00
mockGetSignatureStatus();
// mock SystemProgram.createAccount transaction for Token.createNewToken()
mockSendTransaction();
mockGetSignatureStatus();
// mock Token.createNewToken() transaction
mockSendTransaction();
2019-04-10 14:40:49 -07:00
mockGetSignatureStatus(null);
2018-10-06 11:23:18 -07:00
mockGetSignatureStatus();
}
[testToken, initialOwnerTokenAccount] = await Token.createNewToken(
connection,
initialOwner,
new TokenAmount(10000),
'Test token',
'TEST',
2018-11-04 11:41:21 -08:00
2,
2018-10-06 11:23:18 -07:00
);
{
// mock Token.tokenInfo()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [testToken.token.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
1,
2018-11-04 11:41:21 -08:00
16,
39,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
2,
2018-11-04 11:41:21 -08:00
10,
0,
0,
0,
0,
0,
0,
0,
84,
101,
115,
116,
32,
116,
111,
107,
101,
110,
4,
0,
0,
0,
0,
0,
0,
0,
84,
69,
83,
84,
2018-10-06 11:23:18 -07:00
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
}
const tokenInfo = await testToken.tokenInfo();
expect(tokenInfo.supply.toNumber()).toBe(10000);
expect(tokenInfo.decimals).toBe(2);
expect(tokenInfo.name).toBe('Test token');
expect(tokenInfo.symbol).toBe('TEST');
{
// mock Token.accountInfo()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [initialOwnerTokenAccount.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
2,
...testToken.token.toBuffer(),
...initialOwner.publicKey.toBuffer(),
2018-11-04 11:41:21 -08:00
16,
39,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
}
const accountInfo = await testToken.accountInfo(initialOwnerTokenAccount);
expect(accountInfo.token.equals(testToken.token)).toBe(true);
expect(accountInfo.owner.equals(initialOwner.publicKey)).toBe(true);
expect(accountInfo.amount.toNumber()).toBe(10000);
expect(accountInfo.source).toBe(null);
expect(accountInfo.originalAmount.toNumber()).toBe(0);
2018-10-06 11:23:18 -07:00
});
test('create new token account', async () => {
const connection = new Connection(url);
2019-03-04 08:06:33 -08:00
connection._disableBlockhashCaching = mockRpcEnabled;
2019-03-05 17:52:13 -08:00
const destOwner = await newAccountWithLamports(connection);
2018-10-06 11:23:18 -07:00
{
// mock SystemProgram.createAccount transaction for Token.newAccount()
mockSendTransaction();
mockGetSignatureStatus();
// mock Token.newAccount() transaction
mockSendTransaction();
mockGetSignatureStatus();
}
const dest = await testToken.newAccount(destOwner);
{
// mock Token.accountInfo()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [dest.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
2,
...testToken.token.toBuffer(),
...destOwner.publicKey.toBuffer(),
2018-11-04 11:41:21 -08:00
0,
0,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
0,
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
}
const accountInfo = await testToken.accountInfo(dest);
expect(accountInfo.token.equals(testToken.token)).toBe(true);
expect(accountInfo.owner.equals(destOwner.publicKey)).toBe(true);
expect(accountInfo.amount.toNumber()).toBe(0);
expect(accountInfo.source).toBe(null);
});
test('transfer', async () => {
const connection = new Connection(url);
2019-03-04 08:06:33 -08:00
connection._disableBlockhashCaching = mockRpcEnabled;
2019-03-05 17:52:13 -08:00
const destOwner = await newAccountWithLamports(connection);
2018-10-06 11:23:18 -07:00
{
// mock SystemProgram.createAccount transaction for Token.newAccount()
mockSendTransaction();
mockGetSignatureStatus();
// mock Token.newAccount() transaction
mockSendTransaction();
mockGetSignatureStatus();
}
const dest = await testToken.newAccount(destOwner);
{
// mock Token.transfer()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [initialOwnerTokenAccount.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
2,
...testToken.token.toBuffer(),
...initialOwner.publicKey.toBuffer(),
2018-11-04 11:41:21 -08:00
123,
0,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
0,
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
// mock Token.transfer() transaction
mockSendTransaction();
mockGetSignatureStatus();
}
await testToken.transfer(initialOwner, initialOwnerTokenAccount, dest, 123);
2018-10-06 11:23:18 -07:00
{
// mock Token.accountInfo()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [dest.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
2,
...testToken.token.toBuffer(),
...dest.toBuffer(),
2018-11-04 11:41:21 -08:00
123,
0,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
0,
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
}
2018-11-16 19:29:14 -08:00
await sleep(500);
2018-10-06 11:23:18 -07:00
const destAccountInfo = await testToken.accountInfo(dest);
expect(destAccountInfo.amount.toNumber()).toBe(123);
});
test('approve/revoke', async () => {
const connection = new Connection(url);
2019-03-04 08:06:33 -08:00
connection._disableBlockhashCaching = mockRpcEnabled;
2019-03-05 17:52:13 -08:00
const delegateOwner = await newAccountWithLamports(connection);
2018-10-06 11:23:18 -07:00
{
// mock SystemProgram.createAccount transaction for Token.newAccount()
mockSendTransaction();
mockGetSignatureStatus();
// mock Token.newAccount() transaction
mockSendTransaction();
mockGetSignatureStatus();
}
2018-11-04 11:41:21 -08:00
const delegate = await testToken.newAccount(
delegateOwner,
initialOwnerTokenAccount,
);
2018-10-06 11:23:18 -07:00
{
// mock Token.approve() transaction
mockSendTransaction();
mockGetSignatureStatus();
}
await testToken.approve(
initialOwner,
initialOwnerTokenAccount,
delegate,
2018-11-04 11:41:21 -08:00
456,
2018-10-06 11:23:18 -07:00
);
{
// mock Token.accountInfo()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [delegate.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
2,
...testToken.token.toBuffer(),
...delegate.toBuffer(),
2018-11-04 11:41:21 -08:00
200,
1,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
1,
...initialOwnerTokenAccount.toBuffer(),
2018-11-04 11:41:21 -08:00
200,
1,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
}
let delegateAccountInfo = await testToken.accountInfo(delegate);
expect(delegateAccountInfo.amount.toNumber()).toBe(456);
expect(delegateAccountInfo.originalAmount.toNumber()).toBe(456);
2018-10-06 11:23:18 -07:00
if (delegateAccountInfo.source === null) {
throw new Error('source should not be null');
} else {
2018-11-04 11:41:21 -08:00
expect(delegateAccountInfo.source.equals(initialOwnerTokenAccount)).toBe(
true,
);
2018-10-06 11:23:18 -07:00
}
{
// mock Token.revoke() transaction
mockSendTransaction();
mockGetSignatureStatus();
}
2018-11-04 11:41:21 -08:00
await testToken.revoke(initialOwner, initialOwnerTokenAccount, delegate);
2018-10-06 11:23:18 -07:00
{
// mock Token.accountInfo()'s getAccountInfo
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [delegate.toBase58()],
},
{
error: null,
result: {
owner: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
2019-03-05 17:52:13 -08:00
lamports: 1,
2019-03-14 13:27:47 -07:00
data: [
2018-10-06 11:23:18 -07:00
2,
...testToken.token.toBuffer(),
...delegate.toBuffer(),
2018-11-04 11:41:21 -08:00
0,
0,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
1,
...initialOwnerTokenAccount.toBuffer(),
2018-11-04 11:41:21 -08:00
0,
0,
0,
0,
0,
0,
0,
0,
2018-10-06 11:23:18 -07:00
],
executable: false,
2018-11-04 11:41:21 -08:00
},
},
2018-10-06 11:23:18 -07:00
]);
}
delegateAccountInfo = await testToken.accountInfo(delegate);
expect(delegateAccountInfo.amount.toNumber()).toBe(0);
expect(delegateAccountInfo.originalAmount.toNumber()).toBe(0);
2018-10-06 11:23:18 -07:00
if (delegateAccountInfo.source === null) {
throw new Error('source should not be null');
} else {
2018-11-04 11:41:21 -08:00
expect(delegateAccountInfo.source.equals(initialOwnerTokenAccount)).toBe(
true,
);
2018-10-06 11:23:18 -07:00
}
});
test('invalid approve', async () => {
if (mockRpcEnabled) {
console.log('non-live test skipped');
return;
}
const connection = new Connection(url);
2019-03-05 17:52:13 -08:00
const owner = await newAccountWithLamports(connection);
2018-10-06 11:23:18 -07:00
const account1 = await testToken.newAccount(owner);
2018-10-10 10:42:00 -07:00
const account1Delegate = await testToken.newAccount(owner, account1);
2018-10-06 11:23:18 -07:00
const account2 = await testToken.newAccount(owner);
2018-10-10 10:42:00 -07:00
// account2 is not a delegate account of account1
2018-10-20 18:21:25 -07:00
await expect(
2018-11-04 11:41:21 -08:00
testToken.approve(owner, account1, account2, 123),
2018-10-06 11:23:18 -07:00
).rejects.toThrow();
2018-10-10 10:42:00 -07:00
// account1Delegate is not a delegate account of account2
2018-10-20 18:21:25 -07:00
await expect(
2018-11-04 11:41:21 -08:00
testToken.approve(owner, account2, account1Delegate, 123),
2018-10-10 10:42:00 -07:00
).rejects.toThrow();
2018-10-06 11:23:18 -07:00
});
test('fail on approve overspend', async () => {
2018-10-06 11:23:18 -07:00
if (mockRpcEnabled) {
console.log('non-live test skipped');
return;
}
const connection = new Connection(url);
2019-03-05 17:52:13 -08:00
const owner = await newAccountWithLamports(connection);
2018-10-06 11:23:18 -07:00
const account1 = await testToken.newAccount(owner);
const account1Delegate = await testToken.newAccount(owner, account1);
const account2 = await testToken.newAccount(owner);
await testToken.transfer(
initialOwner,
initialOwnerTokenAccount,
account1,
10,
);
2018-11-04 11:41:21 -08:00
await testToken.approve(owner, account1, account1Delegate, 2);
2018-10-06 11:23:18 -07:00
let delegateAccountInfo = await testToken.accountInfo(account1Delegate);
expect(delegateAccountInfo.amount.toNumber()).toBe(2);
expect(delegateAccountInfo.originalAmount.toNumber()).toBe(2);
2018-11-04 11:41:21 -08:00
await testToken.transfer(owner, account1Delegate, account2, 1);
2018-10-06 11:23:18 -07:00
delegateAccountInfo = await testToken.accountInfo(account1Delegate);
expect(delegateAccountInfo.amount.toNumber()).toBe(1);
expect(delegateAccountInfo.originalAmount.toNumber()).toBe(2);
2018-11-04 11:41:21 -08:00
await testToken.transfer(owner, account1Delegate, account2, 1);
2018-10-06 11:23:18 -07:00
delegateAccountInfo = await testToken.accountInfo(account1Delegate);
expect(delegateAccountInfo.amount.toNumber()).toBe(0);
expect(delegateAccountInfo.originalAmount.toNumber()).toBe(2);
2018-10-20 18:21:25 -07:00
await expect(
2018-11-04 11:41:21 -08:00
testToken.transfer(owner, account1Delegate, account2, 1),
2018-10-06 11:23:18 -07:00
).rejects.toThrow();
});
2018-10-20 18:21:25 -07:00
test('set owner', async () => {
if (mockRpcEnabled) {
console.log('non-live test skipped');
return;
}
const connection = new Connection(url);
2019-03-05 17:52:13 -08:00
const owner = await newAccountWithLamports(connection);
const newOwner = await newAccountWithLamports(connection);
2018-10-20 18:21:25 -07:00
const account = await testToken.newAccount(owner);
await testToken.setOwner(owner, account, newOwner.publicKey);
await expect(
2018-11-04 11:41:21 -08:00
testToken.setOwner(owner, account, newOwner.publicKey),
2018-10-20 18:21:25 -07:00
).rejects.toThrow();
await testToken.setOwner(newOwner, account, owner.publicKey);
});