Skip to content

Commit fdffbcb

Browse files
committed
Add governed Solana program upgrades
1 parent 20a38f2 commit fdffbcb

11 files changed

Lines changed: 1693 additions & 26 deletions

File tree

README.md

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ Send one or more native instructions. Instruction data accepts `0x` hex, `base64
616616
simulate: false
617617
```
618618

619-
Deploy or upgrade an upgradeable-loader program. Catapult scans the project for `.so` files, so a typical Anchor artifact can be referenced by basename:
619+
For local development, Catapult can deploy or upgrade an upgradeable-loader program directly. These two legacy actions leave the fee-payer as upgrade authority and are not appropriate when Catapult must be authority-free. Catapult scans the project for `.so` files, so a typical Anchor artifact can be referenced by basename:
620620

621621
```yaml
622622
- name: "deploy-counter"
@@ -636,6 +636,78 @@ Deploy or upgrade an upgradeable-loader program. Catapult scans the project for
636636

637637
Deployment outputs include `address`/`programId`, `programDataAddress`, `bufferAddress`, `signatures`, and `slot`. Transaction outputs include `signature`, `slot`, `simulated`, `logs`, and `unitsConsumed`.
638638

639+
#### Authority-free program reservation and Squads upgrades
640+
641+
Production deployments can put a Squads vault in control without publishing a reusable program keypair or giving Catapult lasting authority. First derive the vault, deploy an audited generic inert stub, and atomically transfer the new ProgramData authority to that vault:
642+
643+
```yaml
644+
- name: "reserve-counter"
645+
type: "svm-reserve-program"
646+
arguments:
647+
stub: "{{Program(inert_stub)}}"
648+
finalAuthority:
649+
type: "svm-squads-vault"
650+
arguments:
651+
multisig: "{{squads-multisig}}"
652+
vaultIndex: 0
653+
maxDataLength: 1048576
654+
maxAttempts: 5
655+
```
656+
657+
Omit `programKeypair` for the safe flow. Catapult uploads the address-independent stub first, generates the program key only when it is ready to submit, and includes program creation, stub deployment, and `SetAuthority` in one transaction. If either the program address or ProgramData PDA is dusted before that transaction lands, the transaction rolls back and Catapult retries with a fresh key. The temporary bootstrap authority is generated in memory and is never persisted.
658+
659+
Next upload the exact release artifact to a separate buffer and seal that buffer to the same vault:
660+
661+
```yaml
662+
- name: "counter-buffer"
663+
type: "svm-write-buffer"
664+
arguments:
665+
program: "{{Program(counter)}}"
666+
finalAuthority:
667+
type: "svm-squads-vault"
668+
arguments:
669+
multisig: "{{squads-multisig}}"
670+
vaultIndex: 0
671+
```
672+
673+
Create the Squads vault transaction and proposal. This action verifies the current ProgramData authority, buffer authority, artifact bytes, and reserved capacity before submitting anything. It creates a proposal but does not approve it or vote on it:
674+
675+
```yaml
676+
- name: "propose-counter-upgrade"
677+
type: "svm-squads-propose-upgrade"
678+
arguments:
679+
program: "{{Program(counter)}}"
680+
programId: "{{reserve-counter.address}}"
681+
bufferAddress: "{{counter-buffer.address}}"
682+
multisig: "{{squads-multisig}}"
683+
vaultIndex: 0
684+
memo: "Upgrade counter to the reviewed release artifact"
685+
```
686+
687+
After the Squads members approve the proposal, an executor can run it in a later Catapult invocation:
688+
689+
```yaml
690+
- name: "execute-counter-upgrade"
691+
type: "svm-squads-execute"
692+
arguments:
693+
multisig: "{{squads-multisig}}"
694+
transactionIndex: "{{approved-transaction-index}}"
695+
696+
- name: "verify-counter"
697+
type: "svm-verify-program"
698+
depends_on: ["execute-counter-upgrade"]
699+
arguments:
700+
program: "{{Program(counter)}}"
701+
programId: "{{counter-program-id}}"
702+
expectedAuthority:
703+
type: "svm-squads-vault"
704+
arguments:
705+
multisig: "{{squads-multisig}}"
706+
vaultIndex: 0
707+
```
708+
709+
`svm-prepare-upgrade` performs the same read-only preflight and exposes the Loader-v3 upgrade instruction without creating a Squads proposal. Proposal outputs include `vaultAddress`, `transactionAddress`, `proposalAddress`, and `transactionIndex`. Verification checks the canonical ProgramData PDA, Loader-v3 ownership, exact ELF bytes and zero padding, expected authority, and later-slot visibility.
710+
639711
### `send-transaction`
640712
Send a transaction to the blockchain:
641713

@@ -788,6 +860,15 @@ arguments:
788860
mint: "{{mint}}"
789861
```
790862

863+
Derive a Squads vault authority without hard-coding its PDA:
864+
865+
```yaml
866+
type: "svm-squads-vault"
867+
arguments:
868+
multisig: "{{squads-multisig}}"
869+
vaultIndex: 0
870+
```
871+
791872
### `abi-encode`
792873
ABI-encode function call data:
793874

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"typescript": "^5.3.0"
6060
},
6161
"dependencies": {
62+
"@sqds/multisig": "2.1.4",
6263
"@solana/web3.js": "1.98.0",
6364
"chalk": "^4.1.2",
6465
"commander": "^11.1.0",

0 commit comments

Comments
 (0)