setup.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // SPDX-License-Identifier: Apache-2.0
  2. import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, BpfLoader, Transaction, SystemProgram, BPF_LOADER_PROGRAM_ID, TransactionExpiredBlockheightExceededError } from '@solana/web3.js';
  3. import { AnchorProvider, Program } from '@coral-xyz/anchor';
  4. import fs from 'fs';
  5. const endpoint: string = process.env.RPC_URL || "http://127.0.0.1:8899";
  6. export async function loadContractAndCallConstructor(name: string, args: any[] = [], space: number = 8192):
  7. Promise<{ program: Program, payer: Keypair, provider: AnchorProvider, storage: Keypair, program_key: PublicKey }> {
  8. const {program, payer, provider, program_key} = await loadContract(name);
  9. const storage = Keypair.generate();
  10. await create_account(storage, program_key, space);
  11. await program.methods.new(...args)
  12. .accounts({ dataAccount: storage.publicKey })
  13. .rpc();
  14. return { provider, program, payer, storage, program_key: program_key };
  15. }
  16. export async function loadContract(name: string):
  17. Promise<{program: Program, payer: Keypair, provider: AnchorProvider, program_key: PublicKey}> {
  18. const idl = JSON.parse(fs.readFileSync(`${name}.json`, 'utf8'));
  19. const payer = loadKey('payer.key');
  20. process.env['ANCHOR_WALLET'] = 'payer.key';
  21. const provider = AnchorProvider.local(endpoint);
  22. const program_key = loadKey(`${name}.key`);
  23. const program = new Program(idl, program_key.publicKey, provider)
  24. return {program, payer, provider, program_key: program_key.publicKey};
  25. }
  26. export async function create_account(account: Keypair, programId: PublicKey, space: number) {
  27. const provider = AnchorProvider.local(endpoint);
  28. const lamports = await provider.connection.getMinimumBalanceForRentExemption(space);
  29. const transaction = new Transaction();
  30. transaction.add(
  31. SystemProgram.createAccount({
  32. fromPubkey: provider.wallet.publicKey,
  33. newAccountPubkey: account.publicKey,
  34. lamports,
  35. space,
  36. programId,
  37. }));
  38. await provider.sendAndConfirm(transaction, [account]);
  39. }
  40. export function newConnectionAndPayer(): [Connection, Keypair] {
  41. const connection = newConnection();
  42. const payerAccount = loadKey('payer.key');
  43. return [connection, payerAccount];
  44. }
  45. export async function loadContractWithProvider(provider: AnchorProvider, name: string, args: any[] = [], space: number = 8192):
  46. Promise<{ program: Program, storage: Keypair, program_key: PublicKey }> {
  47. const idl = JSON.parse(fs.readFileSync(`${name}.json`, 'utf8'));
  48. const storage = Keypair.generate();
  49. const program_key = loadKey(`${name}.key`);
  50. await create_account(storage, program_key.publicKey, space);
  51. const program = new Program(idl, program_key.publicKey, provider);
  52. await program.methods.new(...args)
  53. .accounts({ dataAccount: storage.publicKey })
  54. .rpc();
  55. return { program, storage, program_key: program_key.publicKey };
  56. }
  57. function loadKey(filename: string): Keypair {
  58. const contents = fs.readFileSync(filename).toString();
  59. const bs = Uint8Array.from(JSON.parse(contents));
  60. return Keypair.fromSecretKey(bs);
  61. }
  62. async function newAccountWithLamports(connection: Connection): Promise<Keypair> {
  63. const account = Keypair.generate();
  64. console.log('Airdropping SOL to a new wallet ...');
  65. let signature = await connection.requestAirdrop(account.publicKey, 100 * LAMPORTS_PER_SOL);
  66. const latestBlockHash = await connection.getLatestBlockhash();
  67. await connection.confirmTransaction({
  68. blockhash: latestBlockHash.blockhash,
  69. lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
  70. signature,
  71. }, 'confirmed');
  72. return account;
  73. }
  74. async function setup() {
  75. let write_key = (file_name: string, key: Keypair) => {
  76. fs.writeFileSync(file_name, JSON.stringify(Array.from(key.secretKey)));
  77. };
  78. let connection = newConnection();
  79. const payer = await newAccountWithLamports(connection);
  80. write_key('payer.key', payer);
  81. let files = fs.readdirSync(__dirname);
  82. for (let index in files) {
  83. let file = files[index];
  84. if (file.endsWith('.so')) {
  85. let name = file.slice(0, -3);
  86. let program;
  87. if (fs.existsSync(`${name}.key`)) {
  88. program = loadKey(`${name}.key`);
  89. } else {
  90. program = Keypair.generate();
  91. }
  92. console.log(`Loading ${name} at ${program.publicKey}...`);
  93. const program_so = fs.readFileSync(file);
  94. for (let retries = 5; retries > 0; retries -= 1) {
  95. try {
  96. await BpfLoader.load(connection, payer, program, program_so, BPF_LOADER_PROGRAM_ID);
  97. break;
  98. } catch (e) {
  99. if (e instanceof TransactionExpiredBlockheightExceededError) {
  100. console.log(e);
  101. console.log('retrying...');
  102. connection = newConnection();
  103. } else {
  104. throw e;
  105. }
  106. }
  107. }
  108. console.log(`Done loading ${name} ...`);
  109. write_key(`${name}.key`, program);
  110. }
  111. }
  112. // If there was a TransactionExpiredBlockheightExceededError exception, then
  113. // setup.ts does not exit. I have no idea why
  114. process.exit();
  115. }
  116. function newConnection(): Connection {
  117. return new Connection(endpoint, {
  118. commitment: "confirmed",
  119. confirmTransactionInitialTimeout: 1e6,
  120. });
  121. }
  122. if (require.main === module) {
  123. (async () => {
  124. await setup();
  125. })();
  126. }