Skip to content

Commit dc81513

Browse files
committed
Revamp scripts
1 parent f52a265 commit dc81513

File tree

17 files changed

+1218
-192
lines changed

17 files changed

+1218
-192
lines changed

Anchor.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
[toolchain]
2+
13
[features]
2-
seeds = true
4+
resolution = true
35
skip-lint = false
6+
47
[programs.localnet]
58
program_authority_escrow = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
69

710
[registry]
811
url = "https://api.apr.dev"
912

1013
[provider]
11-
cluster = "Localnet"
14+
cluster = "localnet"
1215
wallet = "/home/gbescos/.config/solana/id.json"
1316

1417
[scripts]

Cargo.lock

Lines changed: 58 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,43 @@
11
# program-authority-escrow
22

3-
A minimalistic, stateless program to safely transfer a solana program from one upgrade authority to another one.
3+
A stateless Solana program for safe program authority transfers.
44

5-
The way it works :
6-
- The current authority uses Propose to transfer the authority of any program to a PDA of the escrow seeded by (current_authority, new_authority)
7-
- Once the authority has been transferred two outcomes are possible :
8-
- If the current authority calls Revert, the PDA will give the authority back to the current authority
9-
- If the new authority calls Accept, the PDA will give the authority to the new authority
5+
The current authority calls `propose` to transfer authority to an escrow PDA seeded by `(current_authority, new_authority)`. From there:
6+
- The current authority can call `revert` to reclaim authority
7+
- The new authority can call `accept` to complete the transfer
108

11-
Basically, this program enforces that the new authority has signed before they accept the authority.
12-
This makes errors where we mistakenly transfer the authority to a key that we don't own reversible.
9+
This ensures the new authority has signed before accepting, making accidental transfers to wrong keys reversible.
10+
11+
Build with `cargo build-sbf` and test with `cargo test-sbf`.
12+
13+
## Scripts
14+
15+
TypeScript scripts are provided to interact with the on-chain program. All scripts support:
16+
- File-based keypairs or Ledger hardware wallets
17+
- Squads v3 multisig proposals via `--multisig`
18+
19+
Install dependencies with `yarn install`. See `scripts/helpers.ts` for documentation on CLI arguments.
20+
21+
### Propose
22+
23+
Transfer program authority to the escrow. The current authority proposes the transfer:
1324

14-
## Testing
15-
To run tests:
1625
```shell
17-
cargo test-sbf
26+
yarn propose --keypair <path|ledger> --program <program_address> --authority <new_authority>
1827
```
1928

20-
## Building
21-
To build:
29+
### Accept
30+
31+
Accept a proposed authority transfer. The new authority accepts:
32+
33+
```shell
34+
yarn accept --keypair <path|ledger> --program <program_address> --authority <previous_authority>
35+
```
36+
37+
### Revert
38+
39+
Revert a proposed transfer before it's accepted. The current authority reverts:
2240

2341
```shell
24-
cargo build-sbf
42+
yarn revert --keypair <path|ledger> --program <program_address> --authority <new_authority>
2543
```
26-
Artifacts will be placed at: `target/deploy/*.so`

package.json

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
{
2-
"scripts": {
3-
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4-
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
5-
},
6-
"dependencies": {
7-
"@project-serum/anchor": "^0.26.0"
8-
},
9-
"devDependencies": {
10-
"chai": "^4.3.4",
11-
"mocha": "^9.0.3",
12-
"ts-mocha": "^10.0.0",
13-
"@types/bn.js": "^5.1.0",
14-
"@types/chai": "^4.3.0",
15-
"@types/mocha": "^9.0.0",
16-
"typescript": "^4.3.5",
17-
"prettier": "^2.6.2"
18-
}
2+
"scripts": {
3+
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4+
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check",
5+
"propose": "ts-node scripts/propose.ts",
6+
"revert": "ts-node scripts/revert.ts",
7+
"accept": "ts-node scripts/accept.ts"
8+
},
9+
"dependencies": {
10+
"@coral-xyz/anchor": "^0.30.0",
11+
"@ledgerhq/hw-transport": "^6.31.13",
12+
"@ledgerhq/hw-transport-node-hid": "^6.29.14",
13+
"@sqds/sdk": "^2.0.4",
14+
"@types/minimist": "^1.2.5",
15+
"minimist": "^1.2.8",
16+
"ts-node": "^10.9.2"
17+
},
18+
"devDependencies": {
19+
"@types/bn.js": "^5.1.0",
20+
"@types/chai": "^4.3.0",
21+
"@types/mocha": "^9.0.0",
22+
"chai": "^4.3.4",
23+
"mocha": "^9.0.3",
24+
"prettier": "^2.6.2",
25+
"ts-mocha": "^10.0.0",
26+
"typescript": "^4.3.5"
27+
}
1928
}

programs/program-authority-escrow/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ default = []
2020
custom-heap = []
2121
custom-panic = []
2222
anchor-debug = []
23+
idl-build = ["anchor-lang/idl-build"]
2324

2425
[dependencies]
2526
anchor-lang.workspace = true
@@ -29,4 +30,3 @@ solana-program-test.workspace = true
2930
solana-sdk.workspace = true
3031
tokio.workspace = true
3132
bincode.workspace = true
32-

programs/program-authority-escrow/src/lib.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ use anchor_lang::{
55
prelude::*,
66
solana_program::{
77
bpf_loader_upgradeable,
8-
program::{
9-
invoke,
10-
invoke_signed,
11-
},
8+
program::{invoke, invoke_signed},
129
},
1310
};
1411

@@ -86,29 +83,29 @@ pub mod program_authority_escrow {
8683

8784
#[derive(Accounts)]
8885
pub struct Propose<'info> {
89-
pub current_authority: Signer<'info>,
86+
pub current_authority: Signer<'info>,
9087
/// CHECK: Unchecked new authority, can be a native wallet or a PDA of another program
91-
pub new_authority: AccountInfo<'info>,
88+
pub new_authority: AccountInfo<'info>,
9289
#[account(seeds = [current_authority.key().as_ref(),new_authority.key().as_ref()], bump)]
93-
pub escrow_authority: SystemAccount<'info>,
90+
pub escrow_authority: SystemAccount<'info>,
9491
#[account(executable, constraint = matches!(program_account.as_ref(), UpgradeableLoaderState::Program{..}))]
95-
pub program_account: Account<'info, UpgradeableLoaderState>,
92+
pub program_account: Account<'info, UpgradeableLoaderState>,
9693
#[account(mut, seeds = [program_account.key().as_ref()], bump, seeds::program = bpf_upgradable_loader.key())]
97-
pub program_data: Account<'info, ProgramData>,
94+
pub program_data: Account<'info, ProgramData>,
9895
pub bpf_upgradable_loader: Program<'info, BpfUpgradableLoader>,
9996
}
10097

10198
#[derive(Accounts)]
10299
pub struct Accept<'info> {
103100
/// CHECK: CPI will have the wrong seeds and fail if this is the wrong current authority
104-
pub current_authority: AccountInfo<'info>,
105-
pub new_authority: Signer<'info>,
101+
pub current_authority: AccountInfo<'info>,
102+
pub new_authority: Signer<'info>,
106103
#[account(seeds = [current_authority.key().as_ref(),new_authority.key().as_ref()], bump)]
107-
pub escrow_authority: SystemAccount<'info>,
104+
pub escrow_authority: SystemAccount<'info>,
108105
#[account(executable, constraint = matches!(program_account.as_ref(), UpgradeableLoaderState::Program{..}))]
109-
pub program_account: Account<'info, UpgradeableLoaderState>,
106+
pub program_account: Account<'info, UpgradeableLoaderState>,
110107
#[account(mut, seeds = [program_account.key().as_ref()], bump, seeds::program = bpf_upgradable_loader.key())]
111-
pub program_data: Account<'info, ProgramData>,
108+
pub program_data: Account<'info, ProgramData>,
112109
pub bpf_upgradable_loader: Program<'info, BpfUpgradableLoader>,
113110
}
114111

programs/program-authority-timelock/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ default = []
2020
custom-heap = []
2121
custom-panic = []
2222
anchor-debug = []
23+
idl-build = ["anchor-lang/idl-build"]
2324

2425
[dependencies]
2526
anchor-lang.workspace = true
@@ -29,4 +30,3 @@ solana-program-test.workspace = true
2930
solana-sdk.workspace = true
3031
tokio.workspace = true
3132
bincode.workspace = true
32-

programs/program-authority-timelock/src/lib.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ use anchor_lang::{
55
prelude::*,
66
solana_program::{
77
bpf_loader_upgradeable,
8-
program::{
9-
invoke,
10-
invoke_signed,
11-
},
8+
program::{invoke, invoke_signed},
129
},
1310
};
1411

@@ -74,29 +71,29 @@ pub mod program_authority_timelock {
7471
#[derive(Accounts)]
7572
#[instruction(timestamp : i64)]
7673
pub struct Commit<'info> {
77-
pub current_authority: Signer<'info>,
74+
pub current_authority: Signer<'info>,
7875
/// CHECK: Unchecked new authority, can be a native wallet or a PDA of another program
79-
pub new_authority: AccountInfo<'info>,
76+
pub new_authority: AccountInfo<'info>,
8077
#[account(seeds = [new_authority.key().as_ref(), timestamp.to_be_bytes().as_ref()], bump)]
81-
pub escrow_authority: SystemAccount<'info>,
78+
pub escrow_authority: SystemAccount<'info>,
8279
#[account(executable, constraint = matches!(program_account.as_ref(), UpgradeableLoaderState::Program{..}))]
83-
pub program_account: Account<'info, UpgradeableLoaderState>,
80+
pub program_account: Account<'info, UpgradeableLoaderState>,
8481
#[account(mut, seeds = [program_account.key().as_ref()], bump, seeds::program = bpf_upgradable_loader.key())]
85-
pub program_data: Account<'info, ProgramData>,
82+
pub program_data: Account<'info, ProgramData>,
8683
pub bpf_upgradable_loader: Program<'info, BpfUpgradableLoader>,
8784
}
8885

8986
#[derive(Accounts)]
9087
#[instruction(timestamp : i64)]
9188
pub struct Transfer<'info> {
9289
/// CHECK: Unchecked new authority, can be a native wallet or a PDA of another program
93-
pub new_authority: AccountInfo<'info>,
90+
pub new_authority: AccountInfo<'info>,
9491
#[account(seeds = [new_authority.key().as_ref(), timestamp.to_be_bytes().as_ref()], bump)]
95-
pub escrow_authority: SystemAccount<'info>,
92+
pub escrow_authority: SystemAccount<'info>,
9693
#[account(executable, constraint = matches!(program_account.as_ref(), UpgradeableLoaderState::Program{..}))]
97-
pub program_account: Account<'info, UpgradeableLoaderState>,
94+
pub program_account: Account<'info, UpgradeableLoaderState>,
9895
#[account(mut, seeds = [program_account.key().as_ref()], bump, seeds::program = bpf_upgradable_loader.key())]
99-
pub program_data: Account<'info, ProgramData>,
96+
pub program_data: Account<'info, ProgramData>,
10097
pub bpf_upgradable_loader: Program<'info, BpfUpgradableLoader>,
10198
}
10299

0 commit comments

Comments
 (0)