Skip to content

Commit 5286273

Browse files
authored
Add scripts (#7)
1 parent a3ce2e8 commit 5286273

3 files changed

Lines changed: 245 additions & 0 deletions

File tree

scripts/commit.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { AnchorProvider, BN, Program } from "@project-serum/anchor";
2+
import { LedgerNodeWallet } from "./ledger";
3+
import {Connection, PublicKey} from "@solana/web3.js";
4+
import { ProgramAuthorityTimelock, IDL } from "../target/types/program_authority_timelock";
5+
6+
const PROGRAM_TO_TRANSFER = new PublicKey("pytS9TjG1qyAZypk7n8rw8gfW9sUaqqYyMhJQ4E7JCQ")
7+
const NEW_AUTHORITY = new PublicKey("HVx4oW785bu8QDQ8AwSVfD7H4iuH51ttakc2G5f9XTX8")
8+
const TIMESTAMP = new BN("1706745600")
9+
10+
const BPF_UPGRADABLE_LOADER = new PublicKey(
11+
"BPFLoaderUpgradeab1e11111111111111111111111"
12+
);
13+
const TIMELOCK = new PublicKey("t1monUESMN3oVEoAw9HQkaVX6hUGg3hkhN5wKaTvV5f");
14+
15+
async function main(){
16+
const wallet = await LedgerNodeWallet.createWallet();
17+
const connection = new Connection("https://api.mainnet-beta.solana.com")
18+
const provider = new AnchorProvider(connection,wallet, {})
19+
20+
const program = new Program<ProgramAuthorityTimelock>(IDL, TIMELOCK, provider)
21+
22+
const programDataAccount = PublicKey.findProgramAddressSync(
23+
[PROGRAM_TO_TRANSFER.toBuffer()],
24+
BPF_UPGRADABLE_LOADER
25+
)[0];
26+
27+
const escrowAuthority = PublicKey.findProgramAddressSync(
28+
[NEW_AUTHORITY.toBuffer(), TIMESTAMP.toBuffer("be", 8)],
29+
TIMELOCK
30+
)[0]
31+
32+
await program.methods.commit(TIMESTAMP).accounts({
33+
newAuthority: NEW_AUTHORITY,
34+
programAccount : PROGRAM_TO_TRANSFER,
35+
escrowAuthority: escrowAuthority,
36+
programData: programDataAccount,
37+
bpfUpgradableLoader : BPF_UPGRADABLE_LOADER
38+
}).rpc({skipPreflight: true})
39+
}
40+
41+
main();

scripts/ledger.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { Wallet } from "@project-serum/anchor/dist/cjs/provider";
2+
import Transport, {
3+
StatusCodes,
4+
TransportStatusError,
5+
} from "@ledgerhq/hw-transport";
6+
import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
7+
import { PublicKey, Transaction } from "@solana/web3.js";
8+
9+
export class LedgerNodeWallet implements Wallet {
10+
private _derivationPath: Buffer;
11+
private _transport: Transport;
12+
publicKey: PublicKey;
13+
14+
constructor(
15+
derivationPath: Buffer,
16+
transport: Transport,
17+
publicKey: PublicKey
18+
) {
19+
this._derivationPath = derivationPath;
20+
this._transport = transport;
21+
this.publicKey = publicKey;
22+
}
23+
24+
static async createWallet(
25+
derivationAccount?: number,
26+
derivationChange?: number
27+
): Promise<LedgerNodeWallet> {
28+
const transport = await TransportNodeHid.create();
29+
const derivationPath = getDerivationPath(
30+
derivationAccount,
31+
derivationChange
32+
);
33+
const publicKey = await getPublicKey(transport, derivationPath);
34+
console.log(`Loaded ledger: ${publicKey.toBase58()}}`);
35+
return new LedgerNodeWallet(derivationPath, transport, publicKey);
36+
}
37+
38+
async signTransaction(transaction: Transaction): Promise<Transaction> {
39+
console.log("Please approve the transaction on your ledger device...");
40+
const transport = this._transport;
41+
const publicKey = this.publicKey;
42+
43+
const signature = await signTransaction(
44+
transport,
45+
transaction,
46+
this._derivationPath
47+
);
48+
transaction.addSignature(publicKey, signature);
49+
return transaction;
50+
}
51+
52+
async signAllTransactions(txs: Transaction[]): Promise<Transaction[]> {
53+
return await Promise.all(txs.map((tx) => this.signTransaction(tx)));
54+
}
55+
}
56+
57+
/** @internal */
58+
function getDerivationPath(account?: number, change?: number): Buffer {
59+
const length = account !== undefined ? (change === undefined ? 3 : 4) : 2;
60+
const derivationPath = Buffer.alloc(1 + length * 4);
61+
62+
let offset = derivationPath.writeUInt8(length, 0);
63+
offset = derivationPath.writeUInt32BE(harden(44), offset); // Using BIP44
64+
offset = derivationPath.writeUInt32BE(harden(501), offset); // Solana's BIP44 path
65+
66+
if (account !== undefined) {
67+
offset = derivationPath.writeUInt32BE(harden(account), offset);
68+
if (change !== undefined) {
69+
derivationPath.writeUInt32BE(harden(change), offset);
70+
}
71+
}
72+
73+
return derivationPath;
74+
}
75+
76+
const BIP32_HARDENED_BIT = (1 << 31) >>> 0;
77+
78+
/** @internal */
79+
function harden(n: number): number {
80+
return (n | BIP32_HARDENED_BIT) >>> 0;
81+
}
82+
83+
const INS_GET_PUBKEY = 0x05;
84+
const INS_SIGN_MESSAGE = 0x06;
85+
86+
const P1_NON_CONFIRM = 0x00;
87+
const P1_CONFIRM = 0x01;
88+
89+
const P2_EXTEND = 0x01;
90+
const P2_MORE = 0x02;
91+
92+
const MAX_PAYLOAD = 255;
93+
94+
const LEDGER_CLA = 0xe0;
95+
96+
/** @internal */
97+
export async function getPublicKey(
98+
transport: Transport,
99+
derivationPath: Buffer
100+
): Promise<PublicKey> {
101+
const bytes = await send(
102+
transport,
103+
INS_GET_PUBKEY,
104+
P1_NON_CONFIRM,
105+
derivationPath
106+
);
107+
return new PublicKey(bytes);
108+
}
109+
110+
/** @internal */
111+
export async function signTransaction(
112+
transport: Transport,
113+
transaction: Transaction,
114+
derivationPath: Buffer
115+
): Promise<Buffer> {
116+
const paths = Buffer.alloc(1);
117+
paths.writeUInt8(1, 0);
118+
119+
const message = transaction.serializeMessage();
120+
const data = Buffer.concat([paths, derivationPath, message]);
121+
122+
return await send(transport, INS_SIGN_MESSAGE, P1_CONFIRM, data);
123+
}
124+
125+
/** @internal */
126+
async function send(
127+
transport: Transport,
128+
instruction: number,
129+
p1: number,
130+
data: Buffer
131+
): Promise<Buffer> {
132+
let p2 = 0;
133+
let offset = 0;
134+
135+
if (data.length > MAX_PAYLOAD) {
136+
while (data.length - offset > MAX_PAYLOAD) {
137+
const buffer = data.subarray(offset, offset + MAX_PAYLOAD);
138+
const response = await transport.send(
139+
LEDGER_CLA,
140+
instruction,
141+
p1,
142+
p2 | P2_MORE,
143+
buffer
144+
);
145+
if (response.length !== 2)
146+
throw TransportStatusError(StatusCodes.INCORRECT_DATA);
147+
148+
p2 |= P2_EXTEND;
149+
offset += MAX_PAYLOAD;
150+
}
151+
}
152+
153+
const buffer = data.subarray(offset);
154+
const response = await transport.send(
155+
LEDGER_CLA,
156+
instruction,
157+
p1,
158+
p2,
159+
buffer
160+
);
161+
162+
return response.subarray(0, response.length - 2);
163+
}

scripts/transfer.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { AnchorProvider, BN, Program } from "@project-serum/anchor";
2+
import { LedgerNodeWallet } from "./ledger";
3+
import {Connection, PublicKey} from "@solana/web3.js";
4+
import { ProgramAuthorityTimelock, IDL } from "../target/types/program_authority_timelock";
5+
6+
const PROGRAM_TO_TRANSFER = new PublicKey("pytS9TjG1qyAZypk7n8rw8gfW9sUaqqYyMhJQ4E7JCQ")
7+
const NEW_AUTHORITY = new PublicKey("HVx4oW785bu8QDQ8AwSVfD7H4iuH51ttakc2G5f9XTX8")
8+
const TIMESTAMP = new BN("1706745600")
9+
10+
const BPF_UPGRADABLE_LOADER = new PublicKey(
11+
"BPFLoaderUpgradeab1e11111111111111111111111"
12+
);
13+
const TIMELOCK = new PublicKey("t1monUESMN3oVEoAw9HQkaVX6hUGg3hkhN5wKaTvV5f");
14+
15+
async function main(){
16+
const wallet = await LedgerNodeWallet.createWallet();
17+
const connection = new Connection("https://api.mainnet-beta.solana.com")
18+
const provider = new AnchorProvider(connection,wallet, {})
19+
20+
const program = new Program<ProgramAuthorityTimelock>(IDL, TIMELOCK, provider)
21+
22+
const programDataAccount = PublicKey.findProgramAddressSync(
23+
[PROGRAM_TO_TRANSFER.toBuffer()],
24+
BPF_UPGRADABLE_LOADER
25+
)[0];
26+
27+
const escrowAuthority = PublicKey.findProgramAddressSync(
28+
[NEW_AUTHORITY.toBuffer(), TIMESTAMP.toBuffer("be", 8)],
29+
TIMELOCK
30+
)[0]
31+
32+
await program.methods.transfer(TIMESTAMP).accounts({
33+
newAuthority: NEW_AUTHORITY,
34+
programAccount : PROGRAM_TO_TRANSFER,
35+
escrowAuthority: escrowAuthority,
36+
programData: programDataAccount,
37+
bpfUpgradableLoader : BPF_UPGRADABLE_LOADER
38+
}).rpc({skipPreflight: true})
39+
}
40+
41+
main();

0 commit comments

Comments
 (0)