| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | // @flow
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import bs58 from 'bs58'; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | import {Buffer} from 'buffer'; | 
					
						
							|  |  |  | import {expect} from 'chai'; | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-10 15:43:32 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   Account, | 
					
						
							|  |  |  |   Connection, | 
					
						
							|  |  |  |   SystemProgram, | 
					
						
							|  |  |  |   Transaction, | 
					
						
							|  |  |  |   PublicKey, | 
					
						
							|  |  |  | } from '../src'; | 
					
						
							| 
									
										
										
										
											2020-03-05 09:44:56 -07:00
										 |  |  | import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account'; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | import {MOCK_PORT, url} from './url'; | 
					
						
							|  |  |  | import {helpers, mockRpcResponse, mockServer} from './mocks/rpc-http'; | 
					
						
							|  |  |  | import {stubRpcWebSocket, restoreRpcWebSocket} from './mocks/rpc-websockets'; | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 21:38:11 -07:00
										 |  |  | const expectedData = (authorizedPubkey: PublicKey): [string, string] => { | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  |   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 = new Account(); | 
					
						
							|  |  |  |   mockNonce.publicKey.toBuffer().copy(expectedData, 40); // Hash, 32 bytes
 | 
					
						
							|  |  |  |   expectedData.writeUInt16LE(5000, 72); // feeCalculator, 8 bytes
 | 
					
						
							| 
									
										
										
										
											2020-08-15 21:57:23 -07:00
										 |  |  |   return [expectedData.toString('base64'), 'base64']; | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | describe('Nonce', () => { | 
					
						
							|  |  |  |   let connection: Connection; | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     connection = new Connection(url); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   if (!process.env.TEST_LIVE) { | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       mockServer.start(MOCK_PORT); | 
					
						
							|  |  |  |       stubRpcWebSocket(connection); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     afterEach(() => { | 
					
						
							|  |  |  |       mockServer.stop(); | 
					
						
							|  |  |  |       restoreRpcWebSocket(connection); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('create and query nonce account', async () => { | 
					
						
							|  |  |  |     const from = new Account(); | 
					
						
							|  |  |  |     const nonceAccount = new Account(); | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     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], | 
					
						
							| 
									
										
										
										
											2021-02-17 16:15:09 -08:00
										 |  |  |       commitment: 'confirmed', | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await mockRpcResponse({ | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  |       method: 'getAccountInfo', | 
					
						
							| 
									
										
										
										
											2020-08-15 21:38:11 -07:00
										 |  |  |       params: [ | 
					
						
							|  |  |  |         nonceAccount.publicKey.toBase58(), | 
					
						
							| 
									
										
										
										
											2021-02-17 16:15:09 -08:00
										 |  |  |         {encoding: 'base64', commitment: 'confirmed'}, | 
					
						
							| 
									
										
										
										
											2020-08-15 21:38:11 -07:00
										 |  |  |       ], | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       value: { | 
					
						
							|  |  |  |         owner: '11111111111111111111111111111111', | 
					
						
							|  |  |  |         lamports: minimumAmount, | 
					
						
							|  |  |  |         data: expectedData(from.publicKey), | 
					
						
							|  |  |  |         executable: false, | 
					
						
							| 
									
										
										
										
											2021-02-26 15:06:12 +08:00
										 |  |  |         rentEpoch: 20, | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  |       }, | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       withContext: true, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const nonceAccountData = await connection.getNonce( | 
					
						
							|  |  |  |       nonceAccount.publicKey, | 
					
						
							| 
									
										
										
										
											2021-02-17 16:15:09 -08:00
										 |  |  |       'confirmed', | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('create and query nonce account with seed', async () => { | 
					
						
							|  |  |  |     const from = new Account(); | 
					
						
							|  |  |  |     const seed = 'seed'; | 
					
						
							|  |  |  |     const noncePubkey = await PublicKey.createWithSeed( | 
					
						
							|  |  |  |       from.publicKey, | 
					
						
							| 
									
										
										
										
											2020-09-10 15:43:32 +08:00
										 |  |  |       seed, | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       SystemProgram.programId, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     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], | 
					
						
							| 
									
										
										
										
											2021-02-17 16:15:09 -08:00
										 |  |  |       commitment: 'confirmed', | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await mockRpcResponse({ | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  |       method: 'getAccountInfo', | 
					
						
							| 
									
										
										
										
											2020-08-15 21:38:11 -07:00
										 |  |  |       params: [ | 
					
						
							|  |  |  |         noncePubkey.toBase58(), | 
					
						
							| 
									
										
										
										
											2021-02-17 16:15:09 -08:00
										 |  |  |         {encoding: 'base64', commitment: 'confirmed'}, | 
					
						
							| 
									
										
										
										
											2020-08-15 21:38:11 -07:00
										 |  |  |       ], | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       value: { | 
					
						
							|  |  |  |         owner: '11111111111111111111111111111111', | 
					
						
							|  |  |  |         lamports: minimumAmount, | 
					
						
							|  |  |  |         data: expectedData(from.publicKey), | 
					
						
							|  |  |  |         executable: false, | 
					
						
							| 
									
										
										
										
											2021-02-26 15:06:12 +08:00
										 |  |  |         rentEpoch: 20, | 
					
						
							| 
									
										
										
										
											2020-05-05 13:30:55 +08:00
										 |  |  |       }, | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       withContext: true, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const nonceAccountData = await connection.getNonce( | 
					
						
							|  |  |  |       noncePubkey, | 
					
						
							| 
									
										
										
										
											2021-02-17 16:15:09 -08:00
										 |  |  |       'confirmed', | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-01-02 18:54:43 -07:00
										 |  |  | }); |