Skip to content

Commit

Permalink
chore(example): add solana example for main api
Browse files Browse the repository at this point in the history
  • Loading branch information
RanGojo committed Sep 14, 2024
1 parent ad9c044 commit ab0972b
Show file tree
Hide file tree
Showing 6 changed files with 885 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/main/node-solana/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
19 changes: 19 additions & 0 deletions examples/main/node-solana/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Node.js Example for integrating Rango-SDK for Solana Transactions

### Requirements:

- rango-sdk
- @rango-dev/signer-solana
- solana/web3.js
- bs58
- Node.js >= 20

### How to run the code?

Set up your wallet in index.ts, then run following codes:

```sh
cd /path/to/example/
yarn
node --import=tsx index.ts
```
188 changes: 188 additions & 0 deletions examples/main/node-solana/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// run `node --import=tsx index.ts` in the terminal

import {
CreateTransactionRequest,
MultiRouteRequest,
RangoClient,
TransactionStatus,
TransactionType,
} from 'rango-sdk'
import { findToken } from '../shared/utils/meta.js'
import {
logMeta,
logSelectedTokens,
logWallet,
logTransactionHash,
logRoutes,
logStepStatus,
logConfirmedRoute,
logRouteStep,
} from '../shared/utils/logger.js'
import { setTimeout } from 'timers/promises'
import bs58 from 'bs58'
import {
Keypair,
PublicKey,
Transaction,
VersionedTransaction,
} from '@solana/web3.js'
import {
DefaultSolanaSigner,
setSolanaSignerConfig,
} from '@rango-dev/signer-solana'

// setup wallet key pair
const base58PrivateKey = 'YOUR_BASE58_ENCODED_PRIVATE_KEY'
const privateKey = bs58.decode(base58PrivateKey)
const keypair = Keypair.fromSecretKey(privateKey)
const walletAddress = keypair.publicKey.toString()

// in web based apps, you could use injected provider instead
// e.g. use window.phantom.solana intead of SolanaProvider
class SolanaProvider {
public publicKey?: PublicKey
private keypair: Keypair

constructor(keypair: Keypair) {
this.keypair = keypair
this.publicKey = keypair.publicKey
}

async signTransaction(transaction: VersionedTransaction | Transaction) {
if (transaction instanceof VersionedTransaction)
transaction.sign([this.keypair])
else transaction.sign(this.keypair)
return transaction
}
}
const solana = new SolanaProvider(keypair)

logWallet(walletAddress)

// initiate sdk using your api key
const API_KEY = 'c6381a79-2817-4602-83bf-6a641a409e32'
const rango = new RangoClient(API_KEY)

// get blockchains and tokens meta data
const meta = await rango.getAllMetadata()
logMeta(meta)

// some example tokens for test purpose
const sourceBlockchain = 'SOLANA'
const sourceTokenAddress = null
const targetBlockchain = 'SOLANA'
const targetTokenAddress = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'
const amount = '10000'

// find selected tokens in meta.tokens
const sourceToken = findToken(meta.tokens, sourceBlockchain, sourceTokenAddress)
const targetToken = findToken(meta.tokens, targetBlockchain, targetTokenAddress)
logSelectedTokens(sourceToken, targetToken)

// get route
const routingRequest: MultiRouteRequest = {
from: sourceToken,
to: targetToken,
amount,
slippage: '1.0',
transactionTypes: [TransactionType.SOLANA],
}
const routingResponse = await rango.getAllRoutes(routingRequest)

logRoutes(routingResponse)

if (routingResponse.results.length === 0) {
throw new Error(`No routes found! ${routingResponse.error}`)
}

// confirm one of the routes
const selectedRoute = routingResponse.results[0]

const selectedWallets = selectedRoute.swaps
.flatMap((swap) => [swap.from.blockchain, swap.to.blockchain])
.filter((blockchain, index, self) => self.indexOf(blockchain) === index)
.map((blockchain) => ({ [blockchain]: walletAddress }))
.reduce((acc, obj) => {
return { ...acc, ...obj }
}, {})

const confirmResponse = await rango.confirmRoute({
requestId: selectedRoute.requestId,
selectedWallets,
})

const confirmedRoute = confirmResponse.result

if (!confirmedRoute) {
throw new Error(`Error in confirming route, ${confirmResponse.error}`)
}

logConfirmedRoute(confirmedRoute)

// check wallet to have enough balance or fee using confirm response
for (const validation of confirmedRoute?.validationStatus || []) {
for (const wallet of validation.wallets) {
for (const asset of wallet.requiredAssets) {
if (!asset.ok) {
const message = `Insufficient ${asset.reason}: asset: ${asset.asset.blockchain}.${asset.asset.symbol},
required balance: ${asset.requiredAmount.amount}, current balance: ${asset.currentAmount.amount}`
throw new Error(message)
}
}
}
}

let step = 1
const swapSteps = confirmedRoute.result?.swaps || []
for (const swap of swapSteps) {
logRouteStep(swap, step)

const request: CreateTransactionRequest = {
requestId: confirmedRoute.requestId,
step: step,
userSettings: {
slippage: '1.0',
infiniteApprove: false,
},
validations: {
approve: true,
balance: false,
fee: false,
},
}
let createTransactionResponse = await rango.createTransaction(request)
let tx = createTransactionResponse.transaction
if (!tx) {
throw new Error(
`Error creating the transaction ${createTransactionResponse.error}`
)
}

if (tx.type === TransactionType.SOLANA) {
const defaultSigner = new DefaultSolanaSigner(solana as any)
setSolanaSignerConfig('customRPC', 'https://api.mainnet-beta.solana.com/')

const { hash } = await defaultSigner.signAndSendTx(tx)
logTransactionHash(hash, false)

// track swap status
while (true) {
await setTimeout(10_000)
const state = await rango.checkStatus({
requestId: confirmedRoute.requestId,
step,
txId: hash,
})
logStepStatus(state)

const status = state.status
if (status === TransactionStatus.SUCCESS) {
// we could proceed with the next step of the route
step += 1
break
} else if (status === TransactionStatus.FAILED) {
throw new Error(`Swap failed on step ${step}`)
}
}
}
}
17 changes: 17 additions & 0 deletions examples/main/node-solana/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "node-starter",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"type": "module",
"dependencies": {
"@rango-dev/signer-solana": "^0.31.0",
"@solana/web3.js": "^1.91.4",
"bs58": "^6.0.0",
"rango-sdk": "^0.1.56"
},
"devDependencies": {
"tsx": "^4.17.0"
}
}
Loading

0 comments on commit ab0972b

Please sign in to comment.