Skip to content
Open
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
45 changes: 36 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/smartcontractkit/solana-starter-kit)


# Chainlink Solana Starter Kit

The Chainlink Solana Starter Kit is an [Anchor](https://project-serum.github.io/anchor/getting-started/introduction.html) based program and client that shows developers how to use and interact with [Chainlink Price Feeds on Solana](https://docs.chain.link/solana/). The demo is configured to run on the [Devnet cluster](https://docs.solana.com/clusters#devnet), and is comprised of an on-chain program written in Rust, and an off-chain client written in JavaScript. The program takes parameters and account information from the off-chain client, retrieves the latest price data from the specified Chainlink Price Feed on Devnet, then writes the data out to the specified account, which can then be read by the off-chain client.

## Running the example on Devnet

### Requirements

- [NodeJS 12](https://nodejs.org/en/download/) or higher
- [Rust](https://www.rust-lang.org/tools/install)
- [Solana CLI](https://docs.solanalabs.com/cli/install)
Expand All @@ -41,14 +42,13 @@ npm install
cargo install --git https://github.com/coral-xyz/anchor --tag v0.30.1 anchor-cli --locked
```


Next, generate a new wallet:

```
solana-keygen new -o id.json
```

You should see the public key in the terminal output. Alternatively, you can find the public key with the following CLI command:
You should see the public key in the terminal output. Alternatively, you can find the public key with the following CLI command:

```
solana-keygen pubkey id.json
Expand All @@ -67,10 +67,13 @@ anchor build
```

The build process generates the keypair for your program's account. Before you deploy your program, you must update this public key in this line `lib.rs` file.

```
declare_id!("GEgDWT7Cc8H5S1o2YnTp3umiciazQj5fKbftPXkc2TsL");
```
```

To do this, you need to run the command below:

```
anchor keys sync
```
Expand Down Expand Up @@ -107,13 +110,38 @@ export ANCHOR_PROVIDER_URL='https://api.devnet.solana.com'
export ANCHOR_WALLET='./id.json'
```

Now you are ready to run the JavaScript client. Be sure to pass Chainlink data feed address that you want to query. This can be taken from the [Chainlink Solana Data Feeds page](https://docs.chain.link/docs/solana/data-feeds-solana/), and the value will be defaulted to the Devnet SOL/USD feed address if you don’t specify a value. In this example, we specified the ETH/USD feed:
Now you are ready to run the client. You can choose between the JavaScript version or the TypeScript version.

Be sure to pass Chainlink data feed address that you want to query. This can be taken from the [Chainlink Solana Data Feeds page](https://docs.chain.link/docs/solana/data-feeds-solana/), and the value will be defaulted to the Devnet SOL/USD feed address if you don’t specify a value. In this example, we specified the ETH/USD feed:

#### JavaScript Client

To run the JavaScript client, be sure to pass the Chainlink data feed address that you want to query. You can get the feed address from the [Chainlink Solana Data Feeds page](https://docs.chain.link/docs/solana/data-feeds-solana). If you don’t specify a feed address, the default will be the Devnet SOL/USD feed. In this example, we specify the ETH/USD feed:

```
node client.js \
--program $(solana address -k ./target/deploy/chainlink_solana_demo-keypair.json) \
--feed 669U43LNHx7LsVj95uYksnhXUfWKDsdzVqev3V4Jpw3P
```

#### TypeScript Client

To run the TypeScript client, you'll need to have ts-node installed. To run it, use the following command:

```
node client.js --feed 669U43LNHx7LsVj95uYksnhXUfWKDsdzVqev3V4Jpw3P
npx ts-node client.ts \
--program $(solana address -k ./target/deploy/chainlink_solana_demo-keypair.json) \
--feed 669U43LNHx7LsVj95uYksnhXUfWKDsdzVqev3V4Jpw3P
```

The client will generate a new account and pass it to the deployed program, which will then populate the account with the current price from the specified price feed. The client will then read the price from the account, and output the value to the console.
#### What Happens Next?
The client will generate a new account and pass it to the deployed program.

The program will then populate the account with the current price from the specified price feed.

The client will read the price from the account and output the value to the console.

Both the JavaScript and TypeScript clients will function the same way, so you can choose the version that fits your development environment.

```
Running client...
Expand Down Expand Up @@ -160,7 +188,6 @@ export ANCHOR_WALLET='./id.json'

Next, you can set the value of the `CHAINLINK_FEED_ADDRESS` static variable to the value of the [Price Feed account address](https://docs.chain.link/docs/solana/data-feeds-solana/) that you wish to query. This example queries the ETH/USD feed on Devnet:


```
const CHAINLINK_FEED_ADDRESS="669U43LNHx7LsVj95uYksnhXUfWKDsdzVqev3V4Jpw3P"
```
Expand All @@ -174,6 +201,7 @@ npm run read-data
```

JavaScript:

```
node read-data.js
```
Expand All @@ -192,7 +220,6 @@ pappas99@Pappas solana-starter-kit % npm run read-data
301331000000
```


### Testing

You can execute the [integration test](./tests/chainlink-solana-demo-int-test.ts) with the following command
Expand Down
57 changes: 57 additions & 0 deletions client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as anchor from "@coral-xyz/anchor";
import minimist from "minimist";

// Set up provider and program
anchor.setProvider(anchor.AnchorProvider.env());
const provider = anchor.getProvider();
const program = anchor.workspace.ChainlinkSolanaDemo;

const CHAINLINK_PROGRAM_ID = "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny";
const DIVISOR = 100000000;
const DEFAULT_FEED = "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR"; // SOL/USD
const args = minimist(process.argv.slice(2));
const CHAINLINK_FEED: string = args["feed"] || DEFAULT_FEED;

async function main(): Promise<void> {
console.log(`Interacting with program: ${program.programId}`);

const priceFeedAccount = anchor.web3.Keypair.generate();
console.log(`Generated account: ${priceFeedAccount.publicKey}`);

try {
// Execute the RPC
const txSignature = await program.methods
.execute()
.accounts({
decimal: priceFeedAccount.publicKey,
chainlinkFeed: CHAINLINK_FEED,
chainlinkProgram: CHAINLINK_PROGRAM_ID,
})
.signers([priceFeedAccount])
.rpc();

console.log(`Transaction Signature: ${txSignature}`);

// Fetch and log transaction details
const txDetails = await provider.connection.getTransaction(txSignature, {
commitment: "confirmed",
});

const txLogs = txDetails?.meta?.logMessages ?? [];
console.log("Transaction Logs: ", txLogs);

// Fetch and log price data
const latestPrice = await program.account.decimal.fetch(
priceFeedAccount.publicKey
);

console.log(`Price: ${(latestPrice.value / DIVISOR).toFixed(8)}`);
} catch (error) {
console.error("Error running the program:", error);
}
}

console.log("Running client...");
main()
.then(() => console.log("Success"))
.catch(console.error);
26 changes: 19 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
"dependencies": {
"@chainlink/solana-sdk": "^0.2.2",
"@coral-xyz/anchor": "^0.30.1",
"@types/node": "^22.14.1",
"bn.js": "^5.2.0",
"borsh": "^0.7.0",
"typescript": "^5.5.4"
"typescript": "^5.8.3"
},
"devDependencies": {
"@solana/web3.js": "^1.95.2",
Expand Down
23 changes: 15 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,12 @@
resolved "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz"
integrity sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==

"@types/node@*":
version "17.0.25"
resolved "https://registry.npmjs.org/@types/node/-/node-17.0.25.tgz"
integrity sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w==
"@types/node@*", "@types/node@^22.14.1":
version "22.14.1"
resolved "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz"
integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==
dependencies:
undici-types "~6.21.0"

"@types/node@^12.12.54":
version "12.20.55"
Expand Down Expand Up @@ -1288,10 +1290,15 @@ type-detect@^4.0.0, type-detect@^4.0.5:
resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==

typescript@^5.5.4:
version "5.5.4"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz"
integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
typescript@^5.8.3:
version "5.8.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz"
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==

undici-types@~6.21.0:
version "6.21.0"
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==

utf-8-validate@^5.0.2, utf-8-validate@>=5.0.2:
version "5.0.10"
Expand Down