ChorusOne / solido

Lido for Solana is a Lido-DAO governed liquid staking protocol for the Solana blockchain.
https://chorusone.github.io/solido/
GNU General Public License v3.0
101 stars 44 forks source link

Add a typescript/js SDK for interacting with the Solido program #467

Open ruuda opened 2 years ago

ruuda commented 2 years ago

Summary

There are various parties interacting with Solido from javascript. Until now we just had a dump of some useful snippets on https://docs.solana.lido.fi/development/frontend-integration, but we can do much better than this by offering a library.

Details

We should offer the following functions:

Probably we should parametrize those functions over the addresses, and then also offer one constant that contains the official mainnet addresses.

An attempt at defining this, but I know nothing about Typescript so feel free to correct me here:

// TODO: Is it better to use an interface or class for this?
interface Addresses {
    solidoProgramId: PublicKey;
    solidoInstanceId: PublicKey;
    stSolMintAddress: PublicKey;
}

const MAINNET_ADDRESSES: Addresses = {
    solidoProgramId: web3.PublicKey("CrX7kMhLC3cSsXJdT7JDgqrRVWGnUpX3gfEfxxU2NVLi"),
    solidoInstanceId: web3.PublicKey("49Yi1TKkNyYjPAFdR9LBvoHcUjuPX4Df5T5yv39w2XTn"),
    stSolMintAddress: web3.PublicKey("7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj"),
};

interface Lamports { lamports: BigNumber; }
interface StLamports { stLamports: BigNumber; }

interface ExchangeRate {
    solBalance: Lamports;
    stSolSupply: StLamports;
}

interface Snapshot { /* Should hold the data for all relevant accounts. */ }

// Reads the Solido instance and stSOL mint through getMultipleAccounts.
function getSnapshot(connection: Connection, addrs: Addresses): Snapshot { /* ... */ }

// Or maybe these should be methods on `Snapshot`, that would work as well.
function getTotalValueLocked(snapshot: Snapshot): Lamports { /* ... */ }
function getStSolSupply(snapshot: Snapshot): StLamports { /* ... */ }
function getExchangeRate(snapshot: Snapshot): ExchangeRate { /* ... */ }

function deposit(senderSol: PublicKey, recipientStSol, amount: Lamports): TransactionInstruction { /* ... */ }
// Maybe we can also have an function to build the instruction to initialize the associated token account.

// Note: Withdraw initializes the recipient stake account; it should be a new fresh address.
// Would throw an exception if the amount is too low (can happen due to the stake account rent exemption requirement)
// or too high (can happen due to balancing requirements).
function withdraw(
    snapshot: Snapshot,
    senderStSol: PublicKey,
    recipientWithdrawAuthority: PublicKey,
    recipientStakeAccount: PublicKey,
    amount: StLamports,
): TransactionInstruction { /* ... */ }

Open questions

We can put the thing in this repository. @hritique, I am not very familiar with the js ecosystem ... should we also upload a package to NPM or something?

Also, my impression is that Typescript is taking over, and a Typescript library can be used from js after compilation, right? So probably it is most useful to offer it in Typescript so users who are also using it get maximum type safety, but users who are using legacy js can still use it? I see solana-web3 is also written in Typescript, so that would fit in nicely.

ruuda commented 2 years ago

Also, the code in this repository is currently licensed under the GPLv3, but for a library that is not ideal, we should go with something permissive for this part.

AlexBHarley commented 2 years ago

We already have some of these features pulled together for Steakwallet.

What we could do is separate it out into an MIT based library and someone with more knowhow fills in the rest of the functions. The withdraw functionality is a little complicated, for example, which is what we're blocked on right now

ruuda commented 2 years ago

A work in progress is in #478.