182 lines
4.8 KiB
TypeScript
182 lines
4.8 KiB
TypeScript
import bs58 from 'bs58';
|
|
import {Buffer} from 'buffer';
|
|
import {expect} from 'chai';
|
|
|
|
import {
|
|
Connection,
|
|
SystemProgram,
|
|
Transaction,
|
|
PublicKey,
|
|
Keypair,
|
|
} from '../src';
|
|
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
|
|
import {MOCK_PORT, url} from './url';
|
|
import {helpers, mockRpcResponse, mockServer} from './mocks/rpc-http';
|
|
import {stubRpcWebSocket, restoreRpcWebSocket} from './mocks/rpc-websockets';
|
|
|
|
const expectedData = (authorizedPubkey: PublicKey): [string, string] => {
|
|
const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
|
|
expectedData.writeInt32LE(0, 0); // Version, 4 bytes
|
|
expectedData.writeInt32LE(1, 4); // State, 4 bytes
|
|
authorizedPubkey.toBuffer().copy(expectedData, 8); // authorizedPubkey, 32 bytes
|
|
const mockNonce = Keypair.generate();
|
|
mockNonce.publicKey.toBuffer().copy(expectedData, 40); // Hash, 32 bytes
|
|
expectedData.writeUInt16LE(5000, 72); // feeCalculator, 8 bytes
|
|
return [expectedData.toString('base64'), 'base64'];
|
|
};
|
|
|
|
describe('Nonce', () => {
|
|
let connection: Connection;
|
|
beforeEach(() => {
|
|
connection = new Connection(url);
|
|
});
|
|
|
|
if (mockServer) {
|
|
const server = mockServer;
|
|
beforeEach(() => {
|
|
server.start(MOCK_PORT);
|
|
stubRpcWebSocket(connection);
|
|
});
|
|
|
|
afterEach(() => {
|
|
server.stop();
|
|
restoreRpcWebSocket(connection);
|
|
});
|
|
}
|
|
|
|
it('create and query nonce account', async () => {
|
|
const from = Keypair.generate();
|
|
const nonceAccount = Keypair.generate();
|
|
|
|
await mockRpcResponse({
|
|
method: 'getMinimumBalanceForRentExemption',
|
|
params: [NONCE_ACCOUNT_LENGTH],
|
|
value: 50,
|
|
});
|
|
|
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
|
NONCE_ACCOUNT_LENGTH,
|
|
);
|
|
|
|
await helpers.airdrop({
|
|
connection,
|
|
address: from.publicKey,
|
|
amount: minimumAmount * 2,
|
|
});
|
|
|
|
const transaction = new Transaction().add(
|
|
SystemProgram.createNonceAccount({
|
|
fromPubkey: from.publicKey,
|
|
noncePubkey: nonceAccount.publicKey,
|
|
authorizedPubkey: from.publicKey,
|
|
lamports: minimumAmount,
|
|
}),
|
|
);
|
|
|
|
await helpers.processTransaction({
|
|
connection,
|
|
transaction,
|
|
signers: [from, nonceAccount],
|
|
commitment: 'confirmed',
|
|
});
|
|
|
|
await mockRpcResponse({
|
|
method: 'getAccountInfo',
|
|
params: [
|
|
nonceAccount.publicKey.toBase58(),
|
|
{encoding: 'base64', commitment: 'confirmed'},
|
|
],
|
|
value: {
|
|
owner: '11111111111111111111111111111111',
|
|
lamports: minimumAmount,
|
|
data: expectedData(from.publicKey),
|
|
executable: false,
|
|
rentEpoch: 20,
|
|
},
|
|
withContext: true,
|
|
});
|
|
|
|
const nonceAccountData = await connection.getNonce(
|
|
nonceAccount.publicKey,
|
|
'confirmed',
|
|
);
|
|
if (nonceAccountData === null) {
|
|
expect(nonceAccountData).not.to.be.null;
|
|
return;
|
|
}
|
|
expect(nonceAccountData.authorizedPubkey).to.eql(from.publicKey);
|
|
expect(bs58.decode(nonceAccountData.nonce).length).to.be.greaterThan(30);
|
|
});
|
|
|
|
it('create and query nonce account with seed', async () => {
|
|
const from = Keypair.generate();
|
|
const seed = 'seed';
|
|
const noncePubkey = await PublicKey.createWithSeed(
|
|
from.publicKey,
|
|
seed,
|
|
SystemProgram.programId,
|
|
);
|
|
|
|
await mockRpcResponse({
|
|
method: 'getMinimumBalanceForRentExemption',
|
|
params: [NONCE_ACCOUNT_LENGTH],
|
|
value: 50,
|
|
});
|
|
|
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
|
NONCE_ACCOUNT_LENGTH,
|
|
);
|
|
|
|
await helpers.airdrop({
|
|
connection,
|
|
address: from.publicKey,
|
|
amount: minimumAmount * 2,
|
|
});
|
|
|
|
const transaction = new Transaction().add(
|
|
SystemProgram.createNonceAccount({
|
|
fromPubkey: from.publicKey,
|
|
noncePubkey: noncePubkey,
|
|
basePubkey: from.publicKey,
|
|
seed,
|
|
authorizedPubkey: from.publicKey,
|
|
lamports: minimumAmount,
|
|
}),
|
|
);
|
|
|
|
await helpers.processTransaction({
|
|
connection,
|
|
transaction,
|
|
signers: [from],
|
|
commitment: 'confirmed',
|
|
});
|
|
|
|
await mockRpcResponse({
|
|
method: 'getAccountInfo',
|
|
params: [
|
|
noncePubkey.toBase58(),
|
|
{encoding: 'base64', commitment: 'confirmed'},
|
|
],
|
|
value: {
|
|
owner: '11111111111111111111111111111111',
|
|
lamports: minimumAmount,
|
|
data: expectedData(from.publicKey),
|
|
executable: false,
|
|
rentEpoch: 20,
|
|
},
|
|
withContext: true,
|
|
});
|
|
|
|
const nonceAccountData = await connection.getNonce(
|
|
noncePubkey,
|
|
'confirmed',
|
|
);
|
|
if (nonceAccountData === null) {
|
|
expect(nonceAccountData).not.to.be.null;
|
|
return;
|
|
}
|
|
expect(nonceAccountData.authorizedPubkey).to.eql(from.publicKey);
|
|
expect(bs58.decode(nonceAccountData.nonce).length).to.be.greaterThan(30);
|
|
});
|
|
});
|