| 
									
										
										
										
											2020-01-13 16:17:32 -07:00
										 |  |  | import bs58 from 'bs58'; | 
					
						
							| 
									
										
										
										
											2021-03-15 13:08:10 +08:00
										 |  |  | import invariant from 'assert'; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | import {Buffer} from 'buffer'; | 
					
						
							| 
									
										
										
										
											2019-04-10 12:31:50 -07:00
										 |  |  | import nacl from 'tweetnacl'; | 
					
						
							| 
									
										
										
										
											2021-02-08 00:57:12 +08:00
										 |  |  | import {expect} from 'chai'; | 
					
						
							| 
									
										
										
										
											2019-04-10 12:31:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  | import {Keypair} from '../src/keypair'; | 
					
						
							| 
									
										
										
										
											2019-01-31 02:16:07 -07:00
										 |  |  | import {PublicKey} from '../src/publickey'; | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | import {Transaction} from '../src/transaction'; | 
					
						
							| 
									
										
										
										
											2020-01-06 18:12:04 -07:00
										 |  |  | import {StakeProgram} from '../src/stake-program'; | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | import {SystemProgram} from '../src/system-program'; | 
					
						
							| 
									
										
										
										
											2020-06-11 13:15:14 +08:00
										 |  |  | import {Message} from '../src/message'; | 
					
						
							| 
									
										
										
										
											2021-03-15 13:08:10 +08:00
										 |  |  | import {toBuffer} from '../src/util/to-buffer'; | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | describe('Transaction', () => { | 
					
						
							|  |  |  |   describe('compileMessage', () => { | 
					
						
							|  |  |  |     it('accountKeys are ordered', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |       const payer = Keypair.generate(); | 
					
						
							|  |  |  |       const account2 = Keypair.generate(); | 
					
						
							|  |  |  |       const account3 = Keypair.generate(); | 
					
						
							|  |  |  |       const recentBlockhash = Keypair.generate().publicKey.toBase58(); | 
					
						
							|  |  |  |       const programId = Keypair.generate().publicKey; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       const transaction = new Transaction({recentBlockhash}).add({ | 
					
						
							|  |  |  |         keys: [ | 
					
						
							|  |  |  |           {pubkey: account3.publicKey, isSigner: true, isWritable: false}, | 
					
						
							|  |  |  |           {pubkey: payer.publicKey, isSigner: true, isWritable: true}, | 
					
						
							|  |  |  |           {pubkey: account2.publicKey, isSigner: true, isWritable: true}, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         programId, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       transaction.setSigners( | 
					
						
							|  |  |  |         payer.publicKey, | 
					
						
							|  |  |  |         account2.publicKey, | 
					
						
							|  |  |  |         account3.publicKey, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const message = transaction.compileMessage(); | 
					
						
							|  |  |  |       expect(message.accountKeys[0]).to.eql(payer.publicKey); | 
					
						
							|  |  |  |       expect(message.accountKeys[1]).to.eql(account2.publicKey); | 
					
						
							|  |  |  |       expect(message.accountKeys[2]).to.eql(account3.publicKey); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     it('payer is first account meta', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |       const payer = Keypair.generate(); | 
					
						
							|  |  |  |       const other = Keypair.generate(); | 
					
						
							|  |  |  |       const recentBlockhash = Keypair.generate().publicKey.toBase58(); | 
					
						
							|  |  |  |       const programId = Keypair.generate().publicKey; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       const transaction = new Transaction({recentBlockhash}).add({ | 
					
						
							|  |  |  |         keys: [ | 
					
						
							|  |  |  |           {pubkey: other.publicKey, isSigner: true, isWritable: true}, | 
					
						
							|  |  |  |           {pubkey: payer.publicKey, isSigner: true, isWritable: true}, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         programId, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       transaction.sign(payer, other); | 
					
						
							|  |  |  |       const message = transaction.compileMessage(); | 
					
						
							|  |  |  |       expect(message.accountKeys[0]).to.eql(payer.publicKey); | 
					
						
							|  |  |  |       expect(message.accountKeys[1]).to.eql(other.publicKey); | 
					
						
							|  |  |  |       expect(message.header.numRequiredSignatures).to.eq(2); | 
					
						
							|  |  |  |       expect(message.header.numReadonlySignedAccounts).to.eq(0); | 
					
						
							|  |  |  |       expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     it('validation', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |       const payer = Keypair.generate(); | 
					
						
							|  |  |  |       const recentBlockhash = Keypair.generate().publicKey.toBase58(); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       const transaction = new Transaction(); | 
					
						
							|  |  |  |       expect(() => { | 
					
						
							|  |  |  |         transaction.compileMessage(); | 
					
						
							|  |  |  |       }).to.throw('Transaction recentBlockhash required'); | 
					
						
							| 
									
										
										
										
											2020-09-10 14:04:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       transaction.recentBlockhash = recentBlockhash; | 
					
						
							| 
									
										
										
										
											2020-09-10 14:04:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       expect(() => { | 
					
						
							|  |  |  |         transaction.compileMessage(); | 
					
						
							|  |  |  |       }).to.throw('Transaction fee payer required'); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |       transaction.setSigners(payer.publicKey, Keypair.generate().publicKey); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       expect(() => { | 
					
						
							|  |  |  |         transaction.compileMessage(); | 
					
						
							|  |  |  |       }).to.throw('unknown signer'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Expect compile to succeed with implicit fee payer from signers
 | 
					
						
							|  |  |  |       transaction.setSigners(payer.publicKey); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |       transaction.compileMessage(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       // Expect compile to succeed with fee payer and no signers
 | 
					
						
							|  |  |  |       transaction.signatures = []; | 
					
						
							|  |  |  |       transaction.feePayer = payer.publicKey; | 
					
						
							|  |  |  |       transaction.compileMessage(); | 
					
						
							| 
									
										
										
										
											2020-09-10 14:04:09 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     it('payer is writable', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |       const payer = Keypair.generate(); | 
					
						
							|  |  |  |       const recentBlockhash = Keypair.generate().publicKey.toBase58(); | 
					
						
							|  |  |  |       const programId = Keypair.generate().publicKey; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       const transaction = new Transaction({recentBlockhash}).add({ | 
					
						
							|  |  |  |         keys: [{pubkey: payer.publicKey, isSigner: true, isWritable: false}], | 
					
						
							|  |  |  |         programId, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       transaction.sign(payer); | 
					
						
							|  |  |  |       const message = transaction.compileMessage(); | 
					
						
							|  |  |  |       expect(message.accountKeys[0]).to.eql(payer.publicKey); | 
					
						
							|  |  |  |       expect(message.header.numRequiredSignatures).to.eq(1); | 
					
						
							|  |  |  |       expect(message.header.numReadonlySignedAccounts).to.eq(0); | 
					
						
							|  |  |  |       expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('partialSign', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const account1 = Keypair.generate(); | 
					
						
							|  |  |  |     const account2 = Keypair.generate(); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
 | 
					
						
							|  |  |  |     const transfer = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: account1.publicKey, | 
					
						
							|  |  |  |       toPubkey: account2.publicKey, | 
					
						
							|  |  |  |       lamports: 123, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const transaction = new Transaction({recentBlockhash}).add(transfer); | 
					
						
							|  |  |  |     transaction.sign(account1, account2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const partialTransaction = new Transaction({recentBlockhash}).add(transfer); | 
					
						
							|  |  |  |     partialTransaction.setSigners(account1.publicKey, account2.publicKey); | 
					
						
							|  |  |  |     expect(partialTransaction.signatures[0].signature).to.be.null; | 
					
						
							|  |  |  |     expect(partialTransaction.signatures[1].signature).to.be.null; | 
					
						
							| 
									
										
										
										
											2020-10-25 09:59:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     partialTransaction.partialSign(account1); | 
					
						
							|  |  |  |     expect(partialTransaction.signatures[0].signature).not.to.be.null; | 
					
						
							|  |  |  |     expect(partialTransaction.signatures[1].signature).to.be.null; | 
					
						
							| 
									
										
										
										
											2020-10-25 09:59:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(() => partialTransaction.serialize()).to.throw(); | 
					
						
							|  |  |  |     expect(() => | 
					
						
							|  |  |  |       partialTransaction.serialize({requireAllSignatures: false}), | 
					
						
							|  |  |  |     ).not.to.throw(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     partialTransaction.partialSign(account2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(partialTransaction.signatures[0].signature).not.to.be.null; | 
					
						
							|  |  |  |     expect(partialTransaction.signatures[1].signature).not.to.be.null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(() => partialTransaction.serialize()).not.to.throw(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(partialTransaction).to.eql(transaction); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-15 13:08:10 +08:00
										 |  |  |     invariant(partialTransaction.signatures[0].signature); | 
					
						
							|  |  |  |     partialTransaction.signatures[0].signature[0] = 0; | 
					
						
							|  |  |  |     expect(() => | 
					
						
							|  |  |  |       partialTransaction.serialize({requireAllSignatures: false}), | 
					
						
							|  |  |  |     ).to.throw(); | 
					
						
							|  |  |  |     expect(() => | 
					
						
							|  |  |  |       partialTransaction.serialize({ | 
					
						
							|  |  |  |         verifySignatures: false, | 
					
						
							|  |  |  |         requireAllSignatures: false, | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |     ).not.to.throw(); | 
					
						
							| 
									
										
										
										
											2020-09-10 14:04:09 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   describe('dedupe', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const payer = Keypair.generate(); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const duplicate1 = payer; | 
					
						
							|  |  |  |     const duplicate2 = payer; | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const recentBlockhash = Keypair.generate().publicKey.toBase58(); | 
					
						
							|  |  |  |     const programId = Keypair.generate().publicKey; | 
					
						
							| 
									
										
										
										
											2020-09-10 14:04:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     it('setSigners', () => { | 
					
						
							|  |  |  |       const transaction = new Transaction({recentBlockhash}).add({ | 
					
						
							|  |  |  |         keys: [ | 
					
						
							|  |  |  |           {pubkey: duplicate1.publicKey, isSigner: true, isWritable: true}, | 
					
						
							|  |  |  |           {pubkey: payer.publicKey, isSigner: false, isWritable: true}, | 
					
						
							|  |  |  |           {pubkey: duplicate2.publicKey, isSigner: true, isWritable: false}, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         programId, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       transaction.setSigners( | 
					
						
							|  |  |  |         payer.publicKey, | 
					
						
							|  |  |  |         duplicate1.publicKey, | 
					
						
							|  |  |  |         duplicate2.publicKey, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(transaction.signatures).to.have.length(1); | 
					
						
							|  |  |  |       expect(transaction.signatures[0].publicKey).to.eql(payer.publicKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const message = transaction.compileMessage(); | 
					
						
							|  |  |  |       expect(message.accountKeys[0]).to.eql(payer.publicKey); | 
					
						
							|  |  |  |       expect(message.header.numRequiredSignatures).to.eq(1); | 
					
						
							|  |  |  |       expect(message.header.numReadonlySignedAccounts).to.eq(0); | 
					
						
							|  |  |  |       expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       transaction.signatures; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     it('sign', () => { | 
					
						
							|  |  |  |       const transaction = new Transaction({recentBlockhash}).add({ | 
					
						
							|  |  |  |         keys: [ | 
					
						
							|  |  |  |           {pubkey: duplicate1.publicKey, isSigner: true, isWritable: true}, | 
					
						
							|  |  |  |           {pubkey: payer.publicKey, isSigner: false, isWritable: true}, | 
					
						
							|  |  |  |           {pubkey: duplicate2.publicKey, isSigner: true, isWritable: false}, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         programId, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       transaction.sign(payer, duplicate1, duplicate2); | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       expect(transaction.signatures).to.have.length(1); | 
					
						
							|  |  |  |       expect(transaction.signatures[0].publicKey).to.eql(payer.publicKey); | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       const message = transaction.compileMessage(); | 
					
						
							|  |  |  |       expect(message.accountKeys[0]).to.eql(payer.publicKey); | 
					
						
							|  |  |  |       expect(message.header.numRequiredSignatures).to.eq(1); | 
					
						
							|  |  |  |       expect(message.header.numReadonlySignedAccounts).to.eq(0); | 
					
						
							|  |  |  |       expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |       transaction.signatures; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('transfer signatures', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const account1 = Keypair.generate(); | 
					
						
							|  |  |  |     const account2 = Keypair.generate(); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
 | 
					
						
							|  |  |  |     const transfer1 = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: account1.publicKey, | 
					
						
							|  |  |  |       toPubkey: account2.publicKey, | 
					
						
							|  |  |  |       lamports: 123, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const transfer2 = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: account2.publicKey, | 
					
						
							|  |  |  |       toPubkey: account1.publicKey, | 
					
						
							|  |  |  |       lamports: 123, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const orgTransaction = new Transaction({recentBlockhash}).add( | 
					
						
							|  |  |  |       transfer1, | 
					
						
							|  |  |  |       transfer2, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     orgTransaction.sign(account1, account2); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const newTransaction = new Transaction({ | 
					
						
							|  |  |  |       recentBlockhash: orgTransaction.recentBlockhash, | 
					
						
							|  |  |  |       signatures: orgTransaction.signatures, | 
					
						
							|  |  |  |     }).add(transfer1, transfer2); | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(newTransaction).to.eql(orgTransaction); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('dedup signatures', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const account1 = Keypair.generate(); | 
					
						
							|  |  |  |     const account2 = Keypair.generate(); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
 | 
					
						
							|  |  |  |     const transfer1 = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: account1.publicKey, | 
					
						
							|  |  |  |       toPubkey: account2.publicKey, | 
					
						
							|  |  |  |       lamports: 123, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const transfer2 = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: account1.publicKey, | 
					
						
							|  |  |  |       toPubkey: account2.publicKey, | 
					
						
							|  |  |  |       lamports: 123, | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const orgTransaction = new Transaction({recentBlockhash}).add( | 
					
						
							|  |  |  |       transfer1, | 
					
						
							|  |  |  |       transfer2, | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     orgTransaction.sign(account1); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('use nonce', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const account1 = Keypair.generate(); | 
					
						
							|  |  |  |     const account2 = Keypair.generate(); | 
					
						
							|  |  |  |     const nonceAccount = Keypair.generate(); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const nonce = account2.publicKey.toBase58(); // Fake Nonce hash
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const nonceInfo = { | 
					
						
							|  |  |  |       nonce, | 
					
						
							|  |  |  |       nonceInstruction: SystemProgram.nonceAdvance({ | 
					
						
							|  |  |  |         noncePubkey: nonceAccount.publicKey, | 
					
						
							|  |  |  |         authorizedPubkey: account1.publicKey, | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const transferTransaction = new Transaction({nonceInfo}).add( | 
					
						
							|  |  |  |       SystemProgram.transfer({ | 
					
						
							|  |  |  |         fromPubkey: account1.publicKey, | 
					
						
							|  |  |  |         toPubkey: account2.publicKey, | 
					
						
							|  |  |  |         lamports: 123, | 
					
						
							|  |  |  |       }), | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     transferTransaction.sign(account1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let expectedData = Buffer.alloc(4); | 
					
						
							|  |  |  |     expectedData.writeInt32LE(4, 0); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(transferTransaction.instructions).to.have.length(2); | 
					
						
							|  |  |  |     expect(transferTransaction.instructions[0].programId).to.eql( | 
					
						
							|  |  |  |       SystemProgram.programId, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     expect(transferTransaction.instructions[0].data).to.eql(expectedData); | 
					
						
							|  |  |  |     expect(transferTransaction.recentBlockhash).to.eq(nonce); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const stakeAccount = Keypair.generate(); | 
					
						
							|  |  |  |     const voteAccount = Keypair.generate(); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const stakeTransaction = new Transaction({nonceInfo}).add( | 
					
						
							|  |  |  |       StakeProgram.delegate({ | 
					
						
							|  |  |  |         stakePubkey: stakeAccount.publicKey, | 
					
						
							|  |  |  |         authorizedPubkey: account1.publicKey, | 
					
						
							|  |  |  |         votePubkey: voteAccount.publicKey, | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     stakeTransaction.sign(account1); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(stakeTransaction.instructions).to.have.length(2); | 
					
						
							|  |  |  |     expect(stakeTransaction.instructions[0].programId).to.eql( | 
					
						
							|  |  |  |       SystemProgram.programId, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     expect(stakeTransaction.instructions[0].data).to.eql(expectedData); | 
					
						
							|  |  |  |     expect(stakeTransaction.recentBlockhash).to.eq(nonce); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('parse wire format and serialize', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const sender = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); // Arbitrary known account
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
 | 
					
						
							|  |  |  |     const recipient = new PublicKey( | 
					
						
							|  |  |  |       'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', | 
					
						
							|  |  |  |     ); // Arbitrary known public key
 | 
					
						
							|  |  |  |     const transfer = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: sender.publicKey, | 
					
						
							|  |  |  |       toPubkey: recipient, | 
					
						
							|  |  |  |       lamports: 49, | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const expectedTransaction = new Transaction({ | 
					
						
							|  |  |  |       recentBlockhash, | 
					
						
							|  |  |  |       feePayer: sender.publicKey, | 
					
						
							|  |  |  |     }).add(transfer); | 
					
						
							|  |  |  |     expectedTransaction.sign(sender); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const wireTransaction = Buffer.from( | 
					
						
							|  |  |  |       'AVuErQHaXv0SG0/PchunfxHKt8wMRfMZzqV0tkC5qO6owYxWU2v871AoWywGoFQr4z+q/7mE8lIufNl/kxj+nQ0BAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9Q5/Mtmcn8onFxt47xKj+XdXXd3C8j/FcPu7csUrz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxJrndgN4IFTxep3s6kO0ROug7bEsbx0xxuDkqEvwUusBAgIAAQwCAAAAMQAAAAAAAAA=', | 
					
						
							|  |  |  |       'base64', | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const tx = Transaction.from(wireTransaction); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(tx).to.eql(expectedTransaction); | 
					
						
							|  |  |  |     expect(wireTransaction).to.eql(expectedTransaction.serialize()); | 
					
						
							| 
									
										
										
										
											2020-09-13 09:30:51 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('populate transaction', () => { | 
					
						
							|  |  |  |     const recentBlockhash = new PublicKey(1).toString(); | 
					
						
							|  |  |  |     const message = { | 
					
						
							|  |  |  |       accountKeys: [ | 
					
						
							|  |  |  |         new PublicKey(1).toString(), | 
					
						
							|  |  |  |         new PublicKey(2).toString(), | 
					
						
							|  |  |  |         new PublicKey(3).toString(), | 
					
						
							|  |  |  |         new PublicKey(4).toString(), | 
					
						
							|  |  |  |         new PublicKey(5).toString(), | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |       header: { | 
					
						
							|  |  |  |         numReadonlySignedAccounts: 0, | 
					
						
							|  |  |  |         numReadonlyUnsignedAccounts: 3, | 
					
						
							|  |  |  |         numRequiredSignatures: 2, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       instructions: [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           accounts: [1, 2, 3], | 
					
						
							|  |  |  |           data: bs58.encode(Buffer.alloc(5).fill(9)), | 
					
						
							|  |  |  |           programIdIndex: 4, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |       recentBlockhash, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const signatures = [ | 
					
						
							|  |  |  |       bs58.encode(Buffer.alloc(64).fill(1)), | 
					
						
							|  |  |  |       bs58.encode(Buffer.alloc(64).fill(2)), | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const transaction = Transaction.populate(new Message(message), signatures); | 
					
						
							|  |  |  |     expect(transaction.instructions).to.have.length(1); | 
					
						
							|  |  |  |     expect(transaction.signatures).to.have.length(2); | 
					
						
							|  |  |  |     expect(transaction.recentBlockhash).to.eq(recentBlockhash); | 
					
						
							| 
									
										
										
										
											2020-03-03 16:05:50 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('serialize unsigned transaction', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const sender = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); // Arbitrary known account
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
 | 
					
						
							|  |  |  |     const recipient = new PublicKey( | 
					
						
							|  |  |  |       'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', | 
					
						
							|  |  |  |     ); // Arbitrary known public key
 | 
					
						
							|  |  |  |     const transfer = SystemProgram.transfer({ | 
					
						
							|  |  |  |       fromPubkey: sender.publicKey, | 
					
						
							|  |  |  |       toPubkey: recipient, | 
					
						
							|  |  |  |       lamports: 49, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const expectedTransaction = new Transaction({recentBlockhash}).add( | 
					
						
							|  |  |  |       transfer, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     // Empty signature array fails.
 | 
					
						
							|  |  |  |     expect(expectedTransaction.signatures).to.have.length(0); | 
					
						
							|  |  |  |     expect(() => { | 
					
						
							|  |  |  |       expectedTransaction.serialize(); | 
					
						
							|  |  |  |     }).to.throw('Transaction fee payer required'); | 
					
						
							|  |  |  |     expect(() => { | 
					
						
							|  |  |  |       expectedTransaction.serialize({verifySignatures: false}); | 
					
						
							|  |  |  |     }).to.throw('Transaction fee payer required'); | 
					
						
							|  |  |  |     expect(() => { | 
					
						
							|  |  |  |       expectedTransaction.serializeMessage(); | 
					
						
							|  |  |  |     }).to.throw('Transaction fee payer required'); | 
					
						
							| 
									
										
										
										
											2018-11-28 10:06:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expectedTransaction.feePayer = sender.publicKey; | 
					
						
							| 
									
										
										
										
											2019-01-31 02:16:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     // Transactions with missing signatures will fail sigverify.
 | 
					
						
							|  |  |  |     expect(() => { | 
					
						
							|  |  |  |       expectedTransaction.serialize(); | 
					
						
							|  |  |  |     }).to.throw('Signature verification failed'); | 
					
						
							| 
									
										
										
										
											2019-05-08 11:00:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     // Serializing without signatures is allowed if sigverify disabled.
 | 
					
						
							|  |  |  |     expectedTransaction.serialize({verifySignatures: false}); | 
					
						
							| 
									
										
										
										
											2019-05-08 11:00:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     // Serializing the message is allowed when signature array has null signatures
 | 
					
						
							|  |  |  |     expectedTransaction.serializeMessage(); | 
					
						
							| 
									
										
										
										
											2020-01-06 18:12:04 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-15 13:08:10 +08:00
										 |  |  |     expectedTransaction.feePayer = undefined; | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expectedTransaction.setSigners(sender.publicKey); | 
					
						
							|  |  |  |     expect(expectedTransaction.signatures).to.have.length(1); | 
					
						
							| 
									
										
										
										
											2019-08-30 17:22:11 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     // Transactions with missing signatures will fail sigverify.
 | 
					
						
							|  |  |  |     expect(() => { | 
					
						
							|  |  |  |       expectedTransaction.serialize(); | 
					
						
							|  |  |  |     }).to.throw('Signature verification failed'); | 
					
						
							| 
									
										
										
										
											2019-11-16 13:16:30 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     // Serializing without signatures is allowed if sigverify disabled.
 | 
					
						
							| 
									
										
										
										
											2020-09-11 15:04:36 -07:00
										 |  |  |     expectedTransaction.serialize({verifySignatures: false}); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Serializing the message is allowed when signature array has null signatures
 | 
					
						
							| 
									
										
										
										
											2020-09-10 14:04:09 +08:00
										 |  |  |     expectedTransaction.serializeMessage(); | 
					
						
							| 
									
										
										
										
											2020-04-23 15:48:22 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const expectedSerializationWithNoSignatures = Buffer.from( | 
					
						
							|  |  |  |       'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + | 
					
						
							|  |  |  |         'AAAAAAAAAAAAAAAAAAABAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9' + | 
					
						
							|  |  |  |         'Q5/Mtmcn8onFxt47xKj+XdXXd3C8j/FcPu7csUrz/AAAAAAAAAAAAAAAAAAAAAAAAAAA' + | 
					
						
							|  |  |  |         'AAAAAAAAAAAAAAAAxJrndgN4IFTxep3s6kO0ROug7bEsbx0xxuDkqEvwUusBAgIAAQwC' + | 
					
						
							|  |  |  |         'AAAAMQAAAAAAAAA=', | 
					
						
							|  |  |  |       'base64', | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     expect(expectedTransaction.serialize({requireAllSignatures: false})).to.eql( | 
					
						
							|  |  |  |       expectedSerializationWithNoSignatures, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Properly signed transaction succeeds
 | 
					
						
							|  |  |  |     expectedTransaction.partialSign(sender); | 
					
						
							|  |  |  |     expect(expectedTransaction.signatures).to.have.length(1); | 
					
						
							|  |  |  |     const expectedSerialization = Buffer.from( | 
					
						
							|  |  |  |       'AVuErQHaXv0SG0/PchunfxHKt8wMRfMZzqV0tkC5qO6owYxWU2v871AoWywGoFQr4z+q/7mE8lIufNl/' + | 
					
						
							|  |  |  |         'kxj+nQ0BAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9Q5/Mtmcn8onFxt47xKj+XdXX' + | 
					
						
							|  |  |  |         'd3C8j/FcPu7csUrz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxJrndgN4IFTxep3s6kO0' + | 
					
						
							|  |  |  |         'ROug7bEsbx0xxuDkqEvwUusBAgIAAQwCAAAAMQAAAAAAAAA=', | 
					
						
							|  |  |  |       'base64', | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     expect(expectedTransaction.serialize()).to.eql(expectedSerialization); | 
					
						
							|  |  |  |     expect(expectedTransaction.signatures).to.have.length(1); | 
					
						
							| 
									
										
										
										
											2020-04-23 15:48:22 -06:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-10-25 09:59:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |   it('deprecated - externally signed stake delegate', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const authority = Keypair.fromSeed(Uint8Array.from(Array(32).fill(1))); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const stake = new PublicKey(2); | 
					
						
							|  |  |  |     const recentBlockhash = new PublicKey(3).toBuffer(); | 
					
						
							|  |  |  |     const vote = new PublicKey(4); | 
					
						
							|  |  |  |     var tx = StakeProgram.delegate({ | 
					
						
							|  |  |  |       stakePubkey: stake, | 
					
						
							|  |  |  |       authorizedPubkey: authority.publicKey, | 
					
						
							|  |  |  |       votePubkey: vote, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const from = authority; | 
					
						
							|  |  |  |     tx.recentBlockhash = bs58.encode(recentBlockhash); | 
					
						
							|  |  |  |     tx.setSigners(from.publicKey); | 
					
						
							|  |  |  |     const tx_bytes = tx.serializeMessage(); | 
					
						
							|  |  |  |     const signature = nacl.sign.detached(tx_bytes, from.secretKey); | 
					
						
							| 
									
										
										
										
											2021-03-15 13:08:10 +08:00
										 |  |  |     tx.addSignature(from.publicKey, toBuffer(signature)); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(tx.verifySignatures()).to.be.true; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('externally signed stake delegate', () => { | 
					
						
							| 
									
										
										
										
											2021-05-07 16:59:51 +08:00
										 |  |  |     const authority = Keypair.fromSeed(Uint8Array.from(Array(32).fill(1))); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     const stake = new PublicKey(2); | 
					
						
							|  |  |  |     const recentBlockhash = new PublicKey(3).toBuffer(); | 
					
						
							|  |  |  |     const vote = new PublicKey(4); | 
					
						
							|  |  |  |     var tx = StakeProgram.delegate({ | 
					
						
							|  |  |  |       stakePubkey: stake, | 
					
						
							|  |  |  |       authorizedPubkey: authority.publicKey, | 
					
						
							|  |  |  |       votePubkey: vote, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const from = authority; | 
					
						
							|  |  |  |     tx.recentBlockhash = bs58.encode(recentBlockhash); | 
					
						
							|  |  |  |     tx.feePayer = from.publicKey; | 
					
						
							|  |  |  |     const tx_bytes = tx.serializeMessage(); | 
					
						
							|  |  |  |     const signature = nacl.sign.detached(tx_bytes, from.secretKey); | 
					
						
							| 
									
										
										
										
											2021-03-15 13:08:10 +08:00
										 |  |  |     tx.addSignature(from.publicKey, toBuffer(signature)); | 
					
						
							| 
									
										
										
										
											2021-02-06 10:59:00 +08:00
										 |  |  |     expect(tx.verifySignatures()).to.be.true; | 
					
						
							| 
									
										
										
										
											2020-10-25 09:59:38 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | }); |