sbv2-solana/javascript/solana.js/scripts/release.ts

201 lines
5.4 KiB
TypeScript

import * as sbv2 from './src';
import { AggregatorAccount, TransactionObject } from './src';
import { setupOutputDir } from './utils';
import * as anchor from '@coral-xyz/anchor';
import { clusterApiUrl, Connection, PublicKey } from '@solana/web3.js';
import { sleep } from '@switchboard-xyz/common';
// import { backOff } from 'exponential-backoff';
import fs from 'fs';
import _ from 'lodash';
import os from 'os';
import path from 'path';
const aggregatorMapPath = path.join(
os.homedir(),
'devnet-migration',
sbv2.SB_V2_PID.toBase58(),
'aggregator_map.csv'
);
async function main() {
const [oldDirPath, oldFeedDirPath, oldJobDirPath] = setupOutputDir(
'2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG'
);
const [newDirPath, newFeedDirPath, newJobDirPath] = setupOutputDir(
sbv2.SB_V2_PID.toBase58()
);
const devnetConnection = new Connection(
process.env.SOLANA_DEVNET_RPC ?? clusterApiUrl('devnet')
);
console.log(`rpcUrl: ${devnetConnection.rpcEndpoint}`);
const payer = sbv2.SwitchboardTestContextV2.loadKeypair(
'~/switchboard_environments_v2/devnet/upgrade_authority/upgrade_authority.json'
);
console.log(`payer: ${payer.publicKey.toBase58()}`);
const newProgram = await sbv2.SwitchboardProgram.load(
'devnet',
devnetConnection,
payer,
sbv2.SB_V2_PID
);
const aggregatorMap = loadAggregatorMap();
const reverseAggregatorMap = new Map(
Array.from(aggregatorMap.entries()).map(r => [r[1], r[0]])
);
console.log(
`Found ${aggregatorMap.size} aggregators that have already been migrated`
);
const oldAggregatorKeys = Array.from(aggregatorMap.keys()).map(
a => new PublicKey(a)
);
const oldAggregators = await fetchAggregators(
devnetConnection,
oldAggregatorKeys,
new PublicKey('2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG')
);
console.log(`Loaded ${oldAggregators.size} old aggregators `);
const newAggregatorKeys = Array.from(aggregatorMap.values()).map(
a => new PublicKey(a)
);
const aggregators = await fetchAggregators(
devnetConnection,
newAggregatorKeys,
sbv2.SB_V2_PID,
payer.publicKey
);
console.log(`Found ${aggregators.size} aggregators to release`);
const txns: Array<TransactionObject> = [];
for (const [aggregatorKey, aggregator] of aggregators.entries()) {
const oldAggregatorKey = reverseAggregatorMap.get(aggregatorKey);
if (!oldAggregatorKey) {
console.log(
`Old aggregator key not found for new aggregator ${aggregatorKey}`
);
continue;
}
const oldAggregator = oldAggregators.get(oldAggregatorKey);
if (!oldAggregator) {
console.log(`Failed to find old aggregator ${oldAggregatorKey}`);
continue;
}
const aggregatorAccount = new AggregatorAccount(
newProgram,
new PublicKey(aggregatorKey)
);
if (aggregator.resolutionMode.kind === 'ModeRoundResolution') {
txns.push(
aggregatorAccount.setSlidingWindowInstruction(payer.publicKey, {
authority: payer,
mode: new sbv2.types.AggregatorResolutionMode.ModeSlidingResolution(),
})
);
}
txns.push(
aggregatorAccount.setAuthorityInstruction(payer.publicKey, {
newAuthority: oldAggregator.authority,
authority: payer,
})
);
}
const packedTxns = TransactionObject.pack(txns);
console.log(`Packed into ${packedTxns.length} txns`);
const recentBlockhash = await devnetConnection.getLatestBlockhash();
const signatures = await newProgram.signAndSendAll(
packedTxns,
{
skipConfrimation: true,
skipPreflight: true,
},
recentBlockhash
);
for (const signature of signatures) {
console.log(`https://explorer.solana.com/tx/${signature}?cluster=devnet`);
}
await sleep(20000);
const parsedTxns = await devnetConnection.getParsedTransactions(signatures);
fs.writeFileSync(
'./set-authority-txns.json',
JSON.stringify(packedTxns, undefined, 2)
);
}
main().catch(error => {
console.error(error);
});
function loadAggregatorMap(): Map<string, string> {
if (!fs.existsSync(aggregatorMapPath)) {
return new Map();
}
const map = new Map();
const fileString = fs.readFileSync(aggregatorMapPath, 'utf-8');
const fileLines = fileString.split('\n').slice(1);
fileLines.forEach(r => {
const [oldPubkey, newPubkey] = r.split(', ');
map.set(oldPubkey, newPubkey);
});
return map;
}
async function fetchAggregators(
connection: Connection,
pubkeys: Array<PublicKey>,
owner: PublicKey,
authority?: PublicKey
): Promise<Map<string, sbv2.types.AggregatorAccountData>> {
const aggregators = new Map<string, sbv2.types.AggregatorAccountData>();
const batches = _.chunk(pubkeys, 100);
for (const batch of batches) {
const accountInfos = await anchor.utils.rpc.getMultipleAccounts(
connection,
batch
);
for (const account of accountInfos) {
if (!account) {
continue;
}
if (!account.account.owner.equals(owner)) {
console.error(
`Aggregator ${account.publicKey} belongs to wrong program, ${account.account.owner}`
);
continue;
}
try {
const aggregator = sbv2.types.AggregatorAccountData.decode(
account.account.data
);
if (!authority || aggregator.authority.equals(authority)) {
aggregators.set(account.publicKey.toBase58(), aggregator);
}
} catch {}
}
}
return aggregators;
}