-
Notifications
You must be signed in to change notification settings - Fork 10
adding verify script with readme and shell #780
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
Open
yashnevatia
wants to merge
12
commits into
main
Choose a base branch
from
solana-tools
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e1c0bbd
adding verify script with readme and shell
yashnevatia 5d3b3d2
into
yashnevatia ceb84d7
docs
yashnevatia 648ba36
docs
yashnevatia 3aac8bf
Merge branch 'main' into solana-tools
yashnevatia cd2588e
lint
yashnevatia 7a31347
Merge branch 'solana-tools' of ssh://github.com/smartcontractkit/chai…
yashnevatia f7459b1
Merge branch 'main' into solana-tools
yashnevatia 073ad92
Merge branch 'main' into solana-tools
yashnevatia c88d6a3
Merge branch 'main' into solana-tools
tt-cll 024af4e
Merge branch 'main' into solana-tools
yashnevatia deeedd7
Merge branch 'main' into solana-tools
yashnevatia File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Solana Onchain Utilities | ||
|
||
A collection of utilities for Solana blockchain development. | ||
|
||
## Developer Notes | ||
|
||
Can we automate both the processes completely? Maybe. | ||
|
||
Will the automation be reliable? Maybe. | ||
- There are some path assumptions we are making | ||
- Anchor version might change | ||
- Verify flow might change | ||
- The verify flow spins up a docker container on every run which is flaky | ||
|
||
Is it worth unreliably automating a process that will happen twice a year? Dont think so. | ||
|
||
Hence, we are deciding to print the commands for the user to run them manually. | ||
If we see the cadence of these proceseses changing, we can invest some more time in automating them. | ||
|
||
## Contract Verification | ||
|
||
https://solana.com/developers/guides/advanced/verified-builds | ||
|
||
### Usage | ||
|
||
1. cd into `chains/solana/scripts` | ||
2. Enter into the nix shell: `nix-shell` | ||
3. Edit the vars in verify.go based on your liking | ||
4. Ensure your wallet is funded with SOL in the env that you have set | ||
5. Run `go run verify.go verify` | ||
6. That will print the command to verify each program. | ||
7. We print the command instead of running them, as the command spins up a docker container on every run. | ||
8. That has been flaky for me. Running each command separately has been reliable (where you delete the docker container manually if the run get stuck) | ||
|
||
|
||
## IDL Upload | ||
|
||
https://www.anchor-lang.com/docs/references/cli#idl-init | ||
|
||
### Usage | ||
|
||
1. cd into `chains/solana/scripts` | ||
2. Enter into the nix shell: `nix-shell` | ||
3. Edit the vars in `verify.go` based on your liking | ||
4. Ensure your wallet is funded with SOL in the env that you have set | ||
5. Run `go run verify.go idl` | ||
6. That will prepare your idl folder in `scripts/idl` (this is different from the idl on github because it contains metada.address which the init command requires) | ||
7. Overwrite `chains/solana/contracts/target/idl` with `scripts/idl` | ||
8. In `chains/solana/contracts/Anchor.toml`, change anchor_version to whatever you get from `anchor -V` (or you will need avm in your shell which is not required according to me) | ||
9. cd into `chains/solana/contracts` (because the `anchor idl init` command needs to be in an anchor workspace) | ||
10. Run the commands printed in Step 2. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ pkgs ? import <nixpkgs> {} }: | ||
|
||
pkgs.mkShell { | ||
buildInputs = [ | ||
|
||
# Rust | ||
pkgs.rustc | ||
pkgs.cargo | ||
|
||
# Networking & Node | ||
pkgs.curl | ||
pkgs.nodejs | ||
# pkgs.pnpm # Uncomment if needed | ||
|
||
# Common build dependencies | ||
pkgs.openssl | ||
pkgs.pkg-config | ||
pkgs.zlib | ||
|
||
# Misc tools | ||
pkgs.git | ||
pkgs.jq | ||
]; | ||
|
||
shellHook = '' | ||
echo "🔧 Dev environment ready" | ||
cargo install solana-verify | ||
cargo install --git https://github.com/coral-xyz/anchor anchor-cli --locked | ||
export PATH="$HOME/.cargo/bin:$PATH" | ||
''; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/BurntSushi/toml" | ||
) | ||
|
||
var ( | ||
// hash of chainlink-ccip commit to verify | ||
CommitHash = "f93a56f0edc533b3a50c07f55182753b4c4b5b69" | ||
|
||
// RPC URL based on environment (cluster) | ||
SolanaRpcUrl = "https://api.devnet.solana.com" | ||
Cluster = "devnet" | ||
|
||
// funded keypair | ||
KeypairPath = "$HOME/.config/solana/id_devnet.json" | ||
) | ||
|
||
const ( | ||
// URL of the repository to verify (FIXED) | ||
RepoUrl = "https://github.com/smartcontractkit/chainlink-ccip" | ||
GithubRepo = "smartcontractkit/chainlink-ccip" | ||
GithubBranchDir = "chains/solana/contracts/Anchor.toml" | ||
// path to the directory containing the contracts (FIXED) | ||
MountPath = "chains/solana/contracts" | ||
) | ||
|
||
// Fetches Anchor.toml from the github repo | ||
func fetchToml() []byte { | ||
url := fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/%s", GithubRepo, CommitHash, GithubBranchDir) | ||
resp, err := http.Get(url) // #nosec G107 -- URL is constructed from trusted constants | ||
if err != nil { | ||
log.Fatalf("HTTP GET failed: %v", err) | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
log.Fatalf("failed to fetch Anchor.toml: status %d", resp.StatusCode) | ||
} | ||
|
||
body, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
log.Fatalf("failed to read response body: %v", err) | ||
} | ||
return body | ||
} | ||
|
||
// Downloads target/idl/<program>.json into ./idl/ | ||
func fetchIDLs(programs map[string]string) error { | ||
|
||
baseURL := fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/chains/solana/contracts/target/idl", GithubRepo, CommitHash) | ||
|
||
if err := os.MkdirAll("idl", 0o755); err != nil { | ||
return fmt.Errorf("creating idl dir: %w", err) | ||
} | ||
|
||
for program := range programs { | ||
url := fmt.Sprintf("%s/%s.json", baseURL, program) | ||
resp, err := http.Get(url) // #nosec G107 -- URL is constructed from trusted constants | ||
if err != nil { | ||
log.Printf("❌ Failed to download IDL for %s: %v", program, err) | ||
continue | ||
} | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
log.Printf("⚠️ Skipping %s: IDL not found (status %d)", program, resp.StatusCode) | ||
continue | ||
} | ||
|
||
outPath := filepath.Join("idl", fmt.Sprintf("%s.json", program)) | ||
outFile, err := os.Create(outPath) | ||
if err != nil { | ||
resp.Body.Close() // Close before continuing | ||
log.Printf("❌ Could not write %s: %v", outPath, err) | ||
continue | ||
} | ||
|
||
_, err = io.Copy(outFile, resp.Body) | ||
resp.Body.Close() // Close after we're done copying | ||
outFile.Close() | ||
if err != nil { | ||
log.Printf("❌ Failed writing IDL for %s: %v", program, err) | ||
} else { | ||
fmt.Printf("✅ Downloaded IDL for %s → %s\n", program, outPath) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Updates each IDL file with the program address | ||
func patchIDLsWithAddresses(programs map[string]string) error { | ||
for program, address := range programs { | ||
idlPath := filepath.Join("idl", program+".json") | ||
|
||
data, err := os.ReadFile(idlPath) | ||
if err != nil { | ||
log.Printf("❌ Could not read %s: %v", idlPath, err) | ||
continue | ||
} | ||
|
||
var idl map[string]interface{} | ||
if err = json.Unmarshal(data, &idl); err != nil { | ||
log.Printf("❌ Invalid JSON in %s: %v", idlPath, err) | ||
continue | ||
} | ||
|
||
// Inject metadata.address | ||
idl["metadata"] = map[string]interface{}{ | ||
"address": address, | ||
} | ||
|
||
// Marshal and write back to file | ||
out, err := json.MarshalIndent(idl, "", " ") | ||
if err != nil { | ||
log.Printf("❌ Failed to re-encode JSON for %s: %v", idlPath, err) | ||
continue | ||
} | ||
|
||
if err = os.WriteFile(idlPath, out, 0644); err != nil { | ||
log.Printf("❌ Could not write updated IDL to %s: %v", idlPath, err) | ||
continue | ||
} | ||
|
||
fmt.Printf("✅ Patched %s with address %s\n", program, address) | ||
} | ||
return nil | ||
} | ||
|
||
func main() { | ||
if len(os.Args) != 2 || (os.Args[1] != "idl" && os.Args[1] != "verify") { | ||
fmt.Println("Please supply either 'idl' or 'verify' as an argument") | ||
os.Exit(1) | ||
} | ||
|
||
mode := os.Args[1] | ||
|
||
anchorData := struct { | ||
Programs struct { | ||
Localnet map[string]string | ||
} | ||
}{} | ||
anchorBytes := fetchToml() | ||
err := toml.Unmarshal(anchorBytes, &anchorData) | ||
if err != nil { | ||
log.Fatal("Failed to unmarshal anchor toml") | ||
} | ||
|
||
if mode == "verify" { | ||
// print the verify commands | ||
for libName, address := range anchorData.Programs.Localnet { | ||
fmt.Printf("🔍 Verifying %s at %s \n", libName, address) | ||
|
||
verifyCmd := []string{ | ||
"solana-verify", "verify-from-repo", RepoUrl, | ||
"--commit-hash", CommitHash, | ||
"--url", SolanaRpcUrl, | ||
"--program-id", address, | ||
"--mount-path", MountPath, | ||
"--library-name", libName, | ||
"--keypair", KeypairPath, | ||
"--skip-prompt", "--remote", | ||
} | ||
|
||
fmt.Println("[DRY RUN]", strings.Join(verifyCmd, " ")) | ||
fmt.Println() | ||
} | ||
return | ||
} | ||
|
||
// fetch the idls | ||
err = fetchIDLs(anchorData.Programs.Localnet) | ||
if err != nil { | ||
log.Fatalf("❌ Failed to fetch IDLs: %v", err) | ||
} | ||
|
||
// update the idl files for idl init | ||
err = patchIDLsWithAddresses(anchorData.Programs.Localnet) | ||
if err != nil { | ||
log.Fatalf("❌ Failed to patch IDLs: %v", err) | ||
} | ||
|
||
// print the idl init commands | ||
for program, address := range anchorData.Programs.Localnet { | ||
fmt.Printf("🔍 Initializing IDL for %s\n", program) | ||
|
||
idlInitCmd := []string{ | ||
"anchor", "idl", "init", "-f", | ||
filepath.Join("target", "idl", program+".json"), | ||
"--provider.cluster", Cluster, | ||
"--provider.wallet", KeypairPath, | ||
address, | ||
} | ||
|
||
fmt.Println("[DRY RUN]", strings.Join(idlInitCmd, " ")) | ||
fmt.Println() | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a thought, if this is going to be a CLI maybe we can set these as overridable config options with these set as defaults