Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scripts #7

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions scripts/commit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { AnchorProvider, BN, Program } from "@project-serum/anchor";
import { LedgerNodeWallet } from "./ledger";
import {Connection, PublicKey} from "@solana/web3.js";
import { ProgramAuthorityTimelock, IDL } from "../target/types/program_authority_timelock";

const PROGRAM_TO_TRANSFER = new PublicKey("pytS9TjG1qyAZypk7n8rw8gfW9sUaqqYyMhJQ4E7JCQ")
const NEW_AUTHORITY = new PublicKey("HVx4oW785bu8QDQ8AwSVfD7H4iuH51ttakc2G5f9XTX8")
const TIMESTAMP = new BN("1706745600")

const BPF_UPGRADABLE_LOADER = new PublicKey(
"BPFLoaderUpgradeab1e11111111111111111111111"
);
const TIMELOCK = new PublicKey("t1monUESMN3oVEoAw9HQkaVX6hUGg3hkhN5wKaTvV5f");

async function main(){
const wallet = await LedgerNodeWallet.createWallet();
const connection = new Connection("https://api.mainnet-beta.solana.com")
const provider = new AnchorProvider(connection,wallet, {})

const program = new Program<ProgramAuthorityTimelock>(IDL, TIMELOCK, provider)

const programDataAccount = PublicKey.findProgramAddressSync(
[PROGRAM_TO_TRANSFER.toBuffer()],
BPF_UPGRADABLE_LOADER
)[0];

const escrowAuthority = PublicKey.findProgramAddressSync(
[NEW_AUTHORITY.toBuffer(), TIMESTAMP.toBuffer("be", 8)],
TIMELOCK
)[0]

await program.methods.commit(TIMESTAMP).accounts({
newAuthority: NEW_AUTHORITY,
programAccount : PROGRAM_TO_TRANSFER,
escrowAuthority: escrowAuthority,
programData: programDataAccount,
bpfUpgradableLoader : BPF_UPGRADABLE_LOADER
}).rpc({skipPreflight: true})
}

main();
163 changes: 163 additions & 0 deletions scripts/ledger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { Wallet } from "@project-serum/anchor/dist/cjs/provider";
import Transport, {
StatusCodes,
TransportStatusError,
} from "@ledgerhq/hw-transport";
import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
import { PublicKey, Transaction } from "@solana/web3.js";

export class LedgerNodeWallet implements Wallet {
private _derivationPath: Buffer;
private _transport: Transport;
publicKey: PublicKey;

constructor(
derivationPath: Buffer,
transport: Transport,
publicKey: PublicKey
) {
this._derivationPath = derivationPath;
this._transport = transport;
this.publicKey = publicKey;
}

static async createWallet(
derivationAccount?: number,
derivationChange?: number
): Promise<LedgerNodeWallet> {
const transport = await TransportNodeHid.create();
const derivationPath = getDerivationPath(
derivationAccount,
derivationChange
);
const publicKey = await getPublicKey(transport, derivationPath);
console.log(`Loaded ledger: ${publicKey.toBase58()}}`);
return new LedgerNodeWallet(derivationPath, transport, publicKey);
}

async signTransaction(transaction: Transaction): Promise<Transaction> {
console.log("Please approve the transaction on your ledger device...");
const transport = this._transport;
const publicKey = this.publicKey;

const signature = await signTransaction(
transport,
transaction,
this._derivationPath
);
transaction.addSignature(publicKey, signature);
return transaction;
}

async signAllTransactions(txs: Transaction[]): Promise<Transaction[]> {
return await Promise.all(txs.map((tx) => this.signTransaction(tx)));
}
}

/** @internal */
function getDerivationPath(account?: number, change?: number): Buffer {
const length = account !== undefined ? (change === undefined ? 3 : 4) : 2;
const derivationPath = Buffer.alloc(1 + length * 4);

let offset = derivationPath.writeUInt8(length, 0);
offset = derivationPath.writeUInt32BE(harden(44), offset); // Using BIP44
offset = derivationPath.writeUInt32BE(harden(501), offset); // Solana's BIP44 path

if (account !== undefined) {
offset = derivationPath.writeUInt32BE(harden(account), offset);
if (change !== undefined) {
derivationPath.writeUInt32BE(harden(change), offset);
}
}

return derivationPath;
}

const BIP32_HARDENED_BIT = (1 << 31) >>> 0;

/** @internal */
function harden(n: number): number {
return (n | BIP32_HARDENED_BIT) >>> 0;
}

const INS_GET_PUBKEY = 0x05;
const INS_SIGN_MESSAGE = 0x06;

const P1_NON_CONFIRM = 0x00;
const P1_CONFIRM = 0x01;

const P2_EXTEND = 0x01;
const P2_MORE = 0x02;

const MAX_PAYLOAD = 255;

const LEDGER_CLA = 0xe0;

/** @internal */
export async function getPublicKey(
transport: Transport,
derivationPath: Buffer
): Promise<PublicKey> {
const bytes = await send(
transport,
INS_GET_PUBKEY,
P1_NON_CONFIRM,
derivationPath
);
return new PublicKey(bytes);
}

/** @internal */
export async function signTransaction(
transport: Transport,
transaction: Transaction,
derivationPath: Buffer
): Promise<Buffer> {
const paths = Buffer.alloc(1);
paths.writeUInt8(1, 0);

const message = transaction.serializeMessage();
const data = Buffer.concat([paths, derivationPath, message]);

return await send(transport, INS_SIGN_MESSAGE, P1_CONFIRM, data);
}

/** @internal */
async function send(
transport: Transport,
instruction: number,
p1: number,
data: Buffer
): Promise<Buffer> {
let p2 = 0;
let offset = 0;

if (data.length > MAX_PAYLOAD) {
while (data.length - offset > MAX_PAYLOAD) {
const buffer = data.subarray(offset, offset + MAX_PAYLOAD);
const response = await transport.send(
LEDGER_CLA,
instruction,
p1,
p2 | P2_MORE,
buffer
);
if (response.length !== 2)
throw TransportStatusError(StatusCodes.INCORRECT_DATA);

p2 |= P2_EXTEND;
offset += MAX_PAYLOAD;
}
}

const buffer = data.subarray(offset);
const response = await transport.send(
LEDGER_CLA,
instruction,
p1,
p2,
buffer
);

return response.subarray(0, response.length - 2);
}
41 changes: 41 additions & 0 deletions scripts/transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { AnchorProvider, BN, Program } from "@project-serum/anchor";
import { LedgerNodeWallet } from "./ledger";
import {Connection, PublicKey} from "@solana/web3.js";
import { ProgramAuthorityTimelock, IDL } from "../target/types/program_authority_timelock";

const PROGRAM_TO_TRANSFER = new PublicKey("pytS9TjG1qyAZypk7n8rw8gfW9sUaqqYyMhJQ4E7JCQ")
const NEW_AUTHORITY = new PublicKey("HVx4oW785bu8QDQ8AwSVfD7H4iuH51ttakc2G5f9XTX8")
const TIMESTAMP = new BN("1706745600")

const BPF_UPGRADABLE_LOADER = new PublicKey(
"BPFLoaderUpgradeab1e11111111111111111111111"
);
const TIMELOCK = new PublicKey("t1monUESMN3oVEoAw9HQkaVX6hUGg3hkhN5wKaTvV5f");

async function main(){
const wallet = await LedgerNodeWallet.createWallet();
const connection = new Connection("https://api.mainnet-beta.solana.com")
const provider = new AnchorProvider(connection,wallet, {})

const program = new Program<ProgramAuthorityTimelock>(IDL, TIMELOCK, provider)

const programDataAccount = PublicKey.findProgramAddressSync(
[PROGRAM_TO_TRANSFER.toBuffer()],
BPF_UPGRADABLE_LOADER
)[0];

const escrowAuthority = PublicKey.findProgramAddressSync(
[NEW_AUTHORITY.toBuffer(), TIMESTAMP.toBuffer("be", 8)],
TIMELOCK
)[0]

await program.methods.transfer(TIMESTAMP).accounts({
newAuthority: NEW_AUTHORITY,
programAccount : PROGRAM_TO_TRANSFER,
escrowAuthority: escrowAuthority,
programData: programDataAccount,
bpfUpgradableLoader : BPF_UPGRADABLE_LOADER
}).rpc({skipPreflight: true})
}

main();
Loading