From a034310039fdb2d5f414112ecebfdb71e4ac4db5 Mon Sep 17 00:00:00 2001 From: GitHub Pages Action Date: Fri, 12 Apr 2024 02:19:44 +0000 Subject: [PATCH] Update GitHub pages from 1e2dbc3 --- 404.html | 4 ++-- administration/index.html | 4 ++-- assets/js/{523ef08d.41a3dcd2.js => 523ef08d.8860e6ad.js} | 2 +- .../{runtime~main.c1f8ed11.js => runtime~main.ba3a7539.js} | 2 +- blog/archive/index.html | 4 ++-- blog/index.html | 4 ++-- blog/tags/index.html | 4 ++-- blog/tags/lido/index.html | 4 ++-- blog/tags/solana/index.html | 4 ++-- blog/test/index.html | 4 ++-- deployments/index.html | 4 ++-- development/building-docker-image/index.html | 4 ++-- development/index.html | 4 ++-- development/price-oracle/index.html | 4 ++-- development/reproducibility/index.html | 4 ++-- development/specification/index.html | 4 ++-- development/specification/solido/balance/index.html | 4 ++-- development/specification/solido/entrypoint/index.html | 4 ++-- development/specification/solido/error/index.html | 4 ++-- development/specification/solido/index.html | 4 ++-- development/specification/solido/instruction/index.html | 4 ++-- development/specification/solido/lib/index.html | 4 ++-- development/specification/solido/logic/index.html | 4 ++-- .../specification/solido/process_management/index.html | 4 ++-- development/specification/solido/processor/index.html | 4 ++-- development/specification/solido/state/index.html | 4 ++-- development/specification/solido/token/index.html | 4 ++-- fees/index.html | 4 ++-- frontend-integration/manual-instructions/index.html | 4 ++-- .../manual-instructions/v1/stake/index.html | 4 ++-- .../manual-instructions/v1/unstake/index.html | 4 ++-- .../manual-instructions/v2/stake/index.html | 4 ++-- .../manual-instructions/v2/unstake/index.html | 4 ++-- frontend-integration/sdk/banner/index.html | 4 ++-- frontend-integration/sdk/errors/index.html | 4 ++-- frontend-integration/sdk/index.html | 4 ++-- frontend-integration/sdk/react-native/index.html | 4 ++-- frontend-integration/sdk/sdk-methods/index.html | 4 ++-- frontend-integration/sdk/stake/index.html | 4 ++-- governance/index.html | 4 ++-- incentives/index.html | 4 ++-- index.html | 4 ++-- internals/commission/index.html | 4 ++-- internals/exchange-rate/index.html | 4 ++-- internals/solana-staking/index.html | 4 ++-- internals/withdrawals/index.html | 4 ++-- manual-withdrawal/cli/index.html | 6 +++--- manual-withdrawal/self-hosted-widget/index.html | 4 ++-- operation/maintenance/index.html | 4 ++-- operation/multisig-guide/index.html | 4 ++-- operation/the-solido-utility/index.html | 4 ++-- overview/index.html | 4 ++-- security/index.html | 4 ++-- staking/Orca-pool-Wormhole-guide/index.html | 4 ++-- staking/ledger/index.html | 4 ++-- staking/migrate-aux-to-ata-guide/index.html | 4 ++-- staking/overview/index.html | 4 ++-- staking/phantom/index.html | 4 ++-- staking/solflare/index.html | 4 ++-- staking/solong/index.html | 4 ++-- validator-onboarding/index.html | 4 ++-- 61 files changed, 121 insertions(+), 121 deletions(-) rename assets/js/{523ef08d.41a3dcd2.js => 523ef08d.8860e6ad.js} (89%) rename assets/js/{runtime~main.c1f8ed11.js => runtime~main.ba3a7539.js} (99%) diff --git a/404.html b/404.html index 9abc41cc..228b217f 100644 --- a/404.html +++ b/404.html @@ -12,13 +12,13 @@ Page Not Found | Lido on Solana - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/administration/index.html b/administration/index.html index 188b4ef5..08623d0a 100644 --- a/administration/index.html +++ b/administration/index.html @@ -12,7 +12,7 @@ Administration | Lido on Solana - + @@ -64,7 +64,7 @@ has the 7 public keys as owners. The upgrade authority of the multisig program was set to the multisig instance itself.
  • Participants verified that they could reproduce the program, and that the list of public keys matched the keys shared earlier on GitHub.
  • - + \ No newline at end of file diff --git a/assets/js/523ef08d.41a3dcd2.js b/assets/js/523ef08d.8860e6ad.js similarity index 89% rename from assets/js/523ef08d.41a3dcd2.js rename to assets/js/523ef08d.8860e6ad.js index a0dc3078..9952abfa 100644 --- a/assets/js/523ef08d.41a3dcd2.js +++ b/assets/js/523ef08d.8860e6ad.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7054],{3905:(t,e,a)=>{a.d(e,{Zo:()=>c,kt:()=>d});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function o(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function l(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var s=n.createContext({}),p=function(t){var e=n.useContext(s),a=e;return t&&(a="function"==typeof t?t(e):l(l({},e),t)),a},c=function(t){var e=p(t.components);return n.createElement(s.Provider,{value:e},t.children)},u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},m=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,o=t.originalType,s=t.parentName,c=i(t,["components","mdxType","originalType","parentName"]),m=p(a),d=r,k=m["".concat(s,".").concat(d)]||m[d]||u[d]||o;return a?n.createElement(k,l(l({ref:e},c),{},{components:a})):n.createElement(k,l({ref:e},c))}));function d(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var o=a.length,l=new Array(o);l[0]=m;var i={};for(var s in e)hasOwnProperty.call(e,s)&&(i[s]=e[s]);i.originalType=t,i.mdxType="string"==typeof t?t:r,l[1]=i;for(var p=2;p{a.r(e),a.d(e,{assets:()=>s,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const o={title:"with CLI"},l="Manual withdraw with CLI",i={unversionedId:"manual-withdrawal/cli",id:"manual-withdrawal/cli",title:"with CLI",description:"1. Environment Setup",source:"@site/docs/manual-withdrawal/cli.md",sourceDirName:"manual-withdrawal",slug:"/manual-withdrawal/cli",permalink:"/manual-withdrawal/cli",draft:!1,tags:[],version:"current",frontMatter:{title:"with CLI"},sidebar:"solidoSidebar",previous:{title:"Lido on Solana was sunset",permalink:"/"},next:{title:"with self-hosted widget",permalink:"/manual-withdrawal/self-hosted-widget"}},s={},p=[{value:"1. Environment Setup",id:"1-environment-setup",level:2},{value:"2. Transfer stSOL to Local Account",id:"2-transfer-stsol-to-local-account",level:2},{value:"3. Withdraw stSOL",id:"3-withdraw-stsol",level:2},{value:"4. Transfer SOL to Main Account",id:"4-transfer-sol-to-main-account",level:2}],c={toc:p};function u(t){let{components:e,...o}=t;return(0,r.kt)("wrapper",(0,n.Z)({},c,o,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"manual-withdraw-with-cli"},"Manual withdraw with CLI"),(0,r.kt)("h2",{id:"1-environment-setup"},"1. Environment Setup"),(0,r.kt)("p",null,"We've prepared a CLI in Solido to simplify your workflow. You'll need to:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Install Rust"),":\nFollow the instructions at ",(0,r.kt)("a",{parentName:"li",href:"https://www.rust-lang.org/tools/install"},"Rust Installation"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source \"$HOME/.cargo/env\"rustup override set 1.60.0\n")),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Install Solana CLI v1.13.4"),":\nVisit ",(0,r.kt)("a",{parentName:"li",href:"https://docs.solana.com/cli/install-solana-cli-tools"},"Solana CLI Installation"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sh -c "$(curl -sSfL https://release.solana.com/v1.13.4/install)"\n')),(0,r.kt)("ol",{start:3},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Install Solido CLI v2.0.0")," from the official GitHub repository:\nSee ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/lidofinance/solido/releases/tag/v2.1.0"},"Solido Releases"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git clone --recurse-submodules -b V2.1 https://github.com/lidofinance/solido solido_v2\ncd solido_v2\ncargo build --release\n")),(0,r.kt)("h2",{id:"2-transfer-stsol-to-local-account"},"2. Transfer stSOL to Local Account"),(0,r.kt)("p",null,"\u26a0\ufe0f ",(0,r.kt)("strong",{parentName:"p"},"Note"),": Our CLI can only work with local keys. Consider using a new account for withdrawals to keep your main wallet secure. The withdrawal operation will utilize the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),": Public key of the local Solana account."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"STSOL_ACCOUNT_PUBKEY")),": Public key of the child stSOL account from ",(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"KEYPAIR_FILE")),": Local file containing the keypair from ",(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"STAKE_ACCOUNT_PUBKEY")),": Public key of the child stake account from ",(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),".")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Create a new local account"),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana-keygen new --outfile ./local-keypair.json\n")),(0,r.kt)("p",null,"Remember the ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"KEYPAIR_FILE"))," path and ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY"))," from the output."),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Verify the new account with ",(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana balance SOL_ACCOUNT_PUBKEY\n")),(0,r.kt)("ol",{start:3},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Transfer stSOL to the local account using ",(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY"))," and ",(0,r.kt)("strong",{parentName:"p"},"note the transaction signature"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Identify ",(0,r.kt)("inlineCode",{parentName:"strong"},"STSOL_ACCOUNT_PUBKEY")),":"))),(0,r.kt)("p",null,"\u26a0\ufe0f After transferring stSOL, a child account for stSOL is created under your local account. To proceed, locate this address by searching your ",(0,r.kt)("strong",{parentName:"p"},"transaction signature")," on ",(0,r.kt)("a",{parentName:"p",href:"https://solscan.io/"},"Solscan")," and saving the ",(0,r.kt)("strong",{parentName:"p"},"Destination")," pubkey found under ",(0,r.kt)("strong",{parentName:"p"},"Instruction Details \u2192#3 - Token Transfer"),"."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"STSOL_ACCOUNT_PUBKEY",src:a(6159).Z,width:"3003",height:"1735"})),(0,r.kt)("h2",{id:"3-withdraw-stsol"},"3. Withdraw stSOL"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Execute the withdrawal")," to your stake account:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./target/release/solido --config ./solido_config.json --keypair-path KEYPAIR_FILE withdraw --amount-st-sol STSOL_AMOUNT\n")),(0,r.kt)("p",null,"Record the ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"STAKE_ACCOUNT_PUBKEY"))," for further steps."),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Deactivate the stake account"),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana deactivate-stake STAKE_ACCOUNT_PUBKEY --fee-payer KEYPAIR_FILE\n")),(0,r.kt)("p",null,"\u26a0\ufe0f Wait for the epoch to end (~1-2 days) for the stake account to become inactive. Check the epoch status on ",(0,r.kt)("a",{parentName:"p",href:"https://explorer.solana.com/"},"Solana Explorer"),"."),(0,r.kt)("h2",{id:"4-transfer-sol-to-main-account"},"4. Transfer SOL to Main Account"),(0,r.kt)("p",null,"After the epoch ends, withdraw SOL from ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"STAKE_ACCOUNT_PUBKEY"))," to your main account, referred to as ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"MAIN_ACCOUNT_PUBKEY")),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana withdraw-stake **STAKE_ACCOUNT_PUBKEY** \\\n**MAIN_ACCOUNT_PUBKEY** SOL_AMOUNT \\\n--fee-payer **KEYPAIR_FILE**\n")))}u.isMDXComponent=!0},6159:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/stsol_account_pubkey-7ad941b94e88d551ce2ce7d949d4335d.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7054],{3905:(t,e,a)=>{a.d(e,{Zo:()=>c,kt:()=>d});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function o(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function l(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var s=n.createContext({}),p=function(t){var e=n.useContext(s),a=e;return t&&(a="function"==typeof t?t(e):l(l({},e),t)),a},c=function(t){var e=p(t.components);return n.createElement(s.Provider,{value:e},t.children)},u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},m=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,o=t.originalType,s=t.parentName,c=i(t,["components","mdxType","originalType","parentName"]),m=p(a),d=r,k=m["".concat(s,".").concat(d)]||m[d]||u[d]||o;return a?n.createElement(k,l(l({ref:e},c),{},{components:a})):n.createElement(k,l({ref:e},c))}));function d(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var o=a.length,l=new Array(o);l[0]=m;var i={};for(var s in e)hasOwnProperty.call(e,s)&&(i[s]=e[s]);i.originalType=t,i.mdxType="string"==typeof t?t:r,l[1]=i;for(var p=2;p{a.r(e),a.d(e,{assets:()=>s,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const o={title:"with CLI"},l="Manual withdraw with CLI",i={unversionedId:"manual-withdrawal/cli",id:"manual-withdrawal/cli",title:"with CLI",description:"1. Environment Setup",source:"@site/docs/manual-withdrawal/cli.md",sourceDirName:"manual-withdrawal",slug:"/manual-withdrawal/cli",permalink:"/manual-withdrawal/cli",draft:!1,tags:[],version:"current",frontMatter:{title:"with CLI"},sidebar:"solidoSidebar",previous:{title:"Lido on Solana was sunset",permalink:"/"},next:{title:"with self-hosted widget",permalink:"/manual-withdrawal/self-hosted-widget"}},s={},p=[{value:"1. Environment Setup",id:"1-environment-setup",level:2},{value:"2. Transfer stSOL to Local Account",id:"2-transfer-stsol-to-local-account",level:2},{value:"3. Withdraw stSOL",id:"3-withdraw-stsol",level:2},{value:"4. Transfer SOL to Main Account",id:"4-transfer-sol-to-main-account",level:2}],c={toc:p};function u(t){let{components:e,...o}=t;return(0,r.kt)("wrapper",(0,n.Z)({},c,o,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"manual-withdraw-with-cli"},"Manual withdraw with CLI"),(0,r.kt)("h2",{id:"1-environment-setup"},"1. Environment Setup"),(0,r.kt)("p",null,"We've prepared a CLI in Solido to simplify your workflow. You'll need to:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Install Rust"),":\nFollow the instructions at ",(0,r.kt)("a",{parentName:"li",href:"https://www.rust-lang.org/tools/install"},"Rust Installation"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source \"$HOME/.cargo/env\"rustup override set 1.60.0\n")),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Install Solana CLI v1.13.4"),":\nVisit ",(0,r.kt)("a",{parentName:"li",href:"https://docs.solana.com/cli/install-solana-cli-tools"},"Solana CLI Installation"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sh -c "$(curl -sSfL https://release.solana.com/v1.13.4/install)"\n')),(0,r.kt)("ol",{start:3},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Install Solido CLI v2.0.0")," from the official GitHub repository:\nSee ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/lidofinance/solido/releases/tag/v2.1.0"},"Solido Releases"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git clone --recurse-submodules -b V2.1 https://github.com/lidofinance/solido solido_v2\ncd solido_v2\ncargo build --release\n")),(0,r.kt)("h2",{id:"2-transfer-stsol-to-local-account"},"2. Transfer stSOL to Local Account"),(0,r.kt)("p",null,"\u26a0\ufe0f ",(0,r.kt)("strong",{parentName:"p"},"Note"),": Our CLI can only work with local keys. Consider using a new account for withdrawals to keep your main wallet secure. The withdrawal operation will utilize the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),": Public key of the local Solana account."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"STSOL_ACCOUNT_PUBKEY")),": Public key of the child stSOL account from ",(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"KEYPAIR_FILE")),": Local file containing the keypair from ",(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"STAKE_ACCOUNT_PUBKEY")),": Public key of the child stake account from ",(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),".")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Create a new local account"),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana-keygen new --outfile ./local-keypair.json\n")),(0,r.kt)("p",null,"Remember the ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"KEYPAIR_FILE"))," path and ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY"))," from the output."),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Verify the new account with ",(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY")),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana balance SOL_ACCOUNT_PUBKEY\n")),(0,r.kt)("ol",{start:3},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Transfer stSOL to the local account using ",(0,r.kt)("inlineCode",{parentName:"strong"},"SOL_ACCOUNT_PUBKEY"))," and ",(0,r.kt)("strong",{parentName:"p"},"note the transaction signature"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("strong",{parentName:"p"},"Identify ",(0,r.kt)("inlineCode",{parentName:"strong"},"STSOL_ACCOUNT_PUBKEY")),":"))),(0,r.kt)("p",null,"\u26a0\ufe0f After transferring stSOL, a child account for stSOL is created under your local account. To proceed, locate this address by searching your ",(0,r.kt)("strong",{parentName:"p"},"transaction signature")," on ",(0,r.kt)("a",{parentName:"p",href:"https://solscan.io/"},"Solscan")," and saving the ",(0,r.kt)("strong",{parentName:"p"},"Destination")," pubkey found under ",(0,r.kt)("strong",{parentName:"p"},"Instruction Details \u2192#3 - Token Transfer"),"."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"STSOL_ACCOUNT_PUBKEY",src:a(6159).Z,width:"3003",height:"1735"})),(0,r.kt)("h2",{id:"3-withdraw-stsol"},"3. Withdraw stSOL"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Execute the withdrawal")," to your stake account:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./target/release/solido --config ./solido_config.json --keypair-path KEYPAIR_FILE withdraw --amount-st-sol STSOL_AMOUNT\n")),(0,r.kt)("p",null,"Record the ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"STAKE_ACCOUNT_PUBKEY"))," for further steps."),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("strong",{parentName:"li"},"Deactivate the stake account"),":")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana deactivate-stake STAKE_ACCOUNT_PUBKEY --keypair KEYPAIR_FILE\n")),(0,r.kt)("p",null,"\u26a0\ufe0f Wait for the epoch to end (~1-2 days) for the stake account to become inactive. Check the epoch status on ",(0,r.kt)("a",{parentName:"p",href:"https://explorer.solana.com/"},"Solana Explorer"),"."),(0,r.kt)("h2",{id:"4-transfer-sol-to-main-account"},"4. Transfer SOL to Main Account"),(0,r.kt)("p",null,"After the epoch ends, withdraw SOL from ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"STAKE_ACCOUNT_PUBKEY"))," to your main account, referred to as ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("inlineCode",{parentName:"strong"},"MAIN_ACCOUNT_PUBKEY")),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"solana withdraw-stake **STAKE_ACCOUNT_PUBKEY** \\\n**MAIN_ACCOUNT_PUBKEY** SOL_AMOUNT \\\n--keypair **KEYPAIR_FILE**\n")))}u.isMDXComponent=!0},6159:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/stsol_account_pubkey-7ad941b94e88d551ce2ce7d949d4335d.png"}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.c1f8ed11.js b/assets/js/runtime~main.ba3a7539.js similarity index 99% rename from assets/js/runtime~main.c1f8ed11.js rename to assets/js/runtime~main.ba3a7539.js index 196728f9..1d67cf67 100644 --- a/assets/js/runtime~main.c1f8ed11.js +++ b/assets/js/runtime~main.ba3a7539.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,c,d,f,t={},b={};function r(e){var a=b[e];if(void 0!==a)return a.exports;var c=b[e]={id:e,loaded:!1,exports:{}};return t[e].call(c.exports,c,c.exports,r),c.loaded=!0,c.exports}r.m=t,r.c=b,e=[],r.O=(a,c,d,f)=>{if(!c){var t=1/0;for(i=0;i=f)&&Object.keys(r.O).every((e=>r.O[e](c[o])))?c.splice(o--,1):(b=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[c,d,f]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var t={};a=a||[null,c({}),c([]),c(c)];for(var b=2&d&&e;"object"==typeof b&&!~a.indexOf(b);b=c(b))Object.getOwnPropertyNames(b).forEach((a=>t[a]=()=>e[a]));return t.default=()=>e,r.d(f,t),f},r.d=(e,a)=>{for(var c in a)r.o(a,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,c)=>(r.f[c](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",56:"c9c041f3",269:"406f324e",274:"405ac2c3",533:"b2b675dd",590:"70d32500",796:"ecc1ec16",1165:"225b42a9",1239:"3bc8a2c6",1372:"1db64337",1440:"c748ea7b",1477:"b2f554cd",1587:"d3da5344",1666:"94ac4f9b",1704:"d3e8705a",1713:"a7023ddc",2150:"caa994b5",2362:"e8193bc1",2368:"201ea4dd",2416:"81eddf9f",2529:"3202b926",2535:"814f3328",2634:"c446cea1",2769:"2d6886a1",2830:"ae4ba08a",3089:"a6aa9e1f",3110:"e073e835",3135:"d6a0ccbe",3608:"9e4087bc",3643:"01fb5850",3686:"4a9007bb",3875:"49469d33",3943:"575b145e",3951:"a4bde7e6",4013:"01a85c17",4321:"3e12e151",4726:"c46802d4",4895:"759c7395",4980:"c352c888",5186:"bdf6fd19",5267:"7c3e884f",6018:"1ba1e146",6103:"ccc49370",6223:"272dcb11",6463:"900689ba",6585:"43cd595a",6653:"db32d859",6697:"e8ce92a9",7054:"523ef08d",7109:"e42d6d1e",7417:"8fe94420",7563:"699bdc89",7918:"17896441",7983:"7c13eef8",8114:"6a809459",8197:"3c2f94fe",8438:"431d3c75",8447:"8aff9d8b",8551:"03675837",8610:"6875c492",8668:"234395f3",8728:"05504477",8908:"6165d255",9225:"c284bd0e",9313:"dbcbb24a",9331:"c5104875",9364:"cd4bffc0",9399:"a36ff0f2",9428:"00634dd8",9514:"1be78505",9520:"43b97ce7",9575:"1570240a"}[e]||e)+"."+{53:"e062c9a0",56:"e1ebd23e",269:"2579189d",274:"ab1e3f2e",533:"27f741ee",590:"4f6422e5",796:"b8533eaa",1165:"e8413ecb",1239:"ebd98d09",1265:"76bd011c",1372:"6991e9a5",1440:"7dc6b846",1477:"e3d0b323",1587:"00582b7b",1666:"ff2967d4",1704:"4ee65e16",1713:"300ccca3",1992:"c90ee607",2150:"02604591",2362:"2fc16a34",2368:"34b3772d",2416:"f35b33ae",2529:"18ab12c3",2535:"3e3053b5",2634:"5271bb1e",2769:"2ef46323",2830:"e0ada06f",3089:"845cad8c",3110:"e353f90f",3135:"d2607f3c",3608:"6b80105a",3643:"a4cf87c2",3686:"10fe59d9",3875:"e83ea9b0",3943:"7777fa0a",3951:"f2cad94f",4013:"055609b1",4321:"28491e46",4726:"b7516a92",4895:"d4832464",4972:"52e708c9",4980:"bbf06457",5037:"f343d3ac",5186:"fd231859",5267:"623aa444",6018:"c9d4b97f",6048:"9ac55a81",6103:"9b55eea8",6223:"2bc5c24c",6463:"5066e474",6585:"9c097641",6653:"a8e1f567",6697:"3ec909ed",7036:"2e5886c6",7054:"41a3dcd2",7109:"6be2521f",7417:"d9580b52",7563:"f24804bb",7918:"6d964049",7983:"97478ff9",8114:"f2dec99f",8197:"f33d3726",8438:"2396460f",8447:"8439b78b",8551:"2ef2a11a",8610:"f37b7b5c",8668:"0f8a4cf8",8728:"b723421d",8908:"333df441",9225:"95ffde95",9313:"61190b28",9331:"4e26ab4f",9364:"0addde40",9399:"d8428382",9428:"7b6c55a1",9514:"0ae24dc3",9520:"0cbf6e76",9575:"a3891e70"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},f="docs:",r.l=(e,a,c,t)=>{if(d[e])d[e].push(a);else{var b,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(s);var f=d[e];if(delete d[e],b.parentNode&&b.parentNode.removeChild(b),f&&f.forEach((e=>e(c))),a)return a(c)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=l.bind(null,b.onerror),b.onload=l.bind(null,b.onload),o&&document.head.appendChild(b)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"7918","935f2afb":"53",c9c041f3:"56","406f324e":"269","405ac2c3":"274",b2b675dd:"533","70d32500":"590",ecc1ec16:"796","225b42a9":"1165","3bc8a2c6":"1239","1db64337":"1372",c748ea7b:"1440",b2f554cd:"1477",d3da5344:"1587","94ac4f9b":"1666",d3e8705a:"1704",a7023ddc:"1713",caa994b5:"2150",e8193bc1:"2362","201ea4dd":"2368","81eddf9f":"2416","3202b926":"2529","814f3328":"2535",c446cea1:"2634","2d6886a1":"2769",ae4ba08a:"2830",a6aa9e1f:"3089",e073e835:"3110",d6a0ccbe:"3135","9e4087bc":"3608","01fb5850":"3643","4a9007bb":"3686","49469d33":"3875","575b145e":"3943",a4bde7e6:"3951","01a85c17":"4013","3e12e151":"4321",c46802d4:"4726","759c7395":"4895",c352c888:"4980",bdf6fd19:"5186","7c3e884f":"5267","1ba1e146":"6018",ccc49370:"6103","272dcb11":"6223","900689ba":"6463","43cd595a":"6585",db32d859:"6653",e8ce92a9:"6697","523ef08d":"7054",e42d6d1e:"7109","8fe94420":"7417","699bdc89":"7563","7c13eef8":"7983","6a809459":"8114","3c2f94fe":"8197","431d3c75":"8438","8aff9d8b":"8447","03675837":"8551","6875c492":"8610","234395f3":"8668","05504477":"8728","6165d255":"8908",c284bd0e:"9225",dbcbb24a:"9313",c5104875:"9331",cd4bffc0:"9364",a36ff0f2:"9399","00634dd8":"9428","1be78505":"9514","43b97ce7":"9520","1570240a":"9575"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,c)=>{var d=r.o(e,a)?e[a]:void 0;if(0!==d)if(d)c.push(d[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var f=new Promise(((c,f)=>d=e[a]=[c,f]));c.push(d[2]=f);var t=r.p+r.u(a),b=new Error;r.l(t,(c=>{if(r.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var f=c&&("load"===c.type?"missing":c.type),t=c&&c.target&&c.target.src;b.message="Loading chunk "+a+" failed.\n("+f+": "+t+")",b.name="ChunkLoadError",b.type=f,b.request=t,d[1](b)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,c)=>{var d,f,t=c[0],b=c[1],o=c[2],n=0;if(t.some((a=>0!==e[a]))){for(d in b)r.o(b,d)&&(r.m[d]=b[d]);if(o)var i=o(r)}for(a&&a(c);n{"use strict";var e,a,c,d,f,t={},b={};function r(e){var a=b[e];if(void 0!==a)return a.exports;var c=b[e]={id:e,loaded:!1,exports:{}};return t[e].call(c.exports,c,c.exports,r),c.loaded=!0,c.exports}r.m=t,r.c=b,e=[],r.O=(a,c,d,f)=>{if(!c){var t=1/0;for(i=0;i=f)&&Object.keys(r.O).every((e=>r.O[e](c[o])))?c.splice(o--,1):(b=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[c,d,f]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var t={};a=a||[null,c({}),c([]),c(c)];for(var b=2&d&&e;"object"==typeof b&&!~a.indexOf(b);b=c(b))Object.getOwnPropertyNames(b).forEach((a=>t[a]=()=>e[a]));return t.default=()=>e,r.d(f,t),f},r.d=(e,a)=>{for(var c in a)r.o(a,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,c)=>(r.f[c](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",56:"c9c041f3",269:"406f324e",274:"405ac2c3",533:"b2b675dd",590:"70d32500",796:"ecc1ec16",1165:"225b42a9",1239:"3bc8a2c6",1372:"1db64337",1440:"c748ea7b",1477:"b2f554cd",1587:"d3da5344",1666:"94ac4f9b",1704:"d3e8705a",1713:"a7023ddc",2150:"caa994b5",2362:"e8193bc1",2368:"201ea4dd",2416:"81eddf9f",2529:"3202b926",2535:"814f3328",2634:"c446cea1",2769:"2d6886a1",2830:"ae4ba08a",3089:"a6aa9e1f",3110:"e073e835",3135:"d6a0ccbe",3608:"9e4087bc",3643:"01fb5850",3686:"4a9007bb",3875:"49469d33",3943:"575b145e",3951:"a4bde7e6",4013:"01a85c17",4321:"3e12e151",4726:"c46802d4",4895:"759c7395",4980:"c352c888",5186:"bdf6fd19",5267:"7c3e884f",6018:"1ba1e146",6103:"ccc49370",6223:"272dcb11",6463:"900689ba",6585:"43cd595a",6653:"db32d859",6697:"e8ce92a9",7054:"523ef08d",7109:"e42d6d1e",7417:"8fe94420",7563:"699bdc89",7918:"17896441",7983:"7c13eef8",8114:"6a809459",8197:"3c2f94fe",8438:"431d3c75",8447:"8aff9d8b",8551:"03675837",8610:"6875c492",8668:"234395f3",8728:"05504477",8908:"6165d255",9225:"c284bd0e",9313:"dbcbb24a",9331:"c5104875",9364:"cd4bffc0",9399:"a36ff0f2",9428:"00634dd8",9514:"1be78505",9520:"43b97ce7",9575:"1570240a"}[e]||e)+"."+{53:"e062c9a0",56:"e1ebd23e",269:"2579189d",274:"ab1e3f2e",533:"27f741ee",590:"4f6422e5",796:"b8533eaa",1165:"e8413ecb",1239:"ebd98d09",1265:"76bd011c",1372:"6991e9a5",1440:"7dc6b846",1477:"e3d0b323",1587:"00582b7b",1666:"ff2967d4",1704:"4ee65e16",1713:"300ccca3",1992:"c90ee607",2150:"02604591",2362:"2fc16a34",2368:"34b3772d",2416:"f35b33ae",2529:"18ab12c3",2535:"3e3053b5",2634:"5271bb1e",2769:"2ef46323",2830:"e0ada06f",3089:"845cad8c",3110:"e353f90f",3135:"d2607f3c",3608:"6b80105a",3643:"a4cf87c2",3686:"10fe59d9",3875:"e83ea9b0",3943:"7777fa0a",3951:"f2cad94f",4013:"055609b1",4321:"28491e46",4726:"b7516a92",4895:"d4832464",4972:"52e708c9",4980:"bbf06457",5037:"f343d3ac",5186:"fd231859",5267:"623aa444",6018:"c9d4b97f",6048:"9ac55a81",6103:"9b55eea8",6223:"2bc5c24c",6463:"5066e474",6585:"9c097641",6653:"a8e1f567",6697:"3ec909ed",7036:"2e5886c6",7054:"8860e6ad",7109:"6be2521f",7417:"d9580b52",7563:"f24804bb",7918:"6d964049",7983:"97478ff9",8114:"f2dec99f",8197:"f33d3726",8438:"2396460f",8447:"8439b78b",8551:"2ef2a11a",8610:"f37b7b5c",8668:"0f8a4cf8",8728:"b723421d",8908:"333df441",9225:"95ffde95",9313:"61190b28",9331:"4e26ab4f",9364:"0addde40",9399:"d8428382",9428:"7b6c55a1",9514:"0ae24dc3",9520:"0cbf6e76",9575:"a3891e70"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},f="docs:",r.l=(e,a,c,t)=>{if(d[e])d[e].push(a);else{var b,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(s);var f=d[e];if(delete d[e],b.parentNode&&b.parentNode.removeChild(b),f&&f.forEach((e=>e(c))),a)return a(c)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=l.bind(null,b.onerror),b.onload=l.bind(null,b.onload),o&&document.head.appendChild(b)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"7918","935f2afb":"53",c9c041f3:"56","406f324e":"269","405ac2c3":"274",b2b675dd:"533","70d32500":"590",ecc1ec16:"796","225b42a9":"1165","3bc8a2c6":"1239","1db64337":"1372",c748ea7b:"1440",b2f554cd:"1477",d3da5344:"1587","94ac4f9b":"1666",d3e8705a:"1704",a7023ddc:"1713",caa994b5:"2150",e8193bc1:"2362","201ea4dd":"2368","81eddf9f":"2416","3202b926":"2529","814f3328":"2535",c446cea1:"2634","2d6886a1":"2769",ae4ba08a:"2830",a6aa9e1f:"3089",e073e835:"3110",d6a0ccbe:"3135","9e4087bc":"3608","01fb5850":"3643","4a9007bb":"3686","49469d33":"3875","575b145e":"3943",a4bde7e6:"3951","01a85c17":"4013","3e12e151":"4321",c46802d4:"4726","759c7395":"4895",c352c888:"4980",bdf6fd19:"5186","7c3e884f":"5267","1ba1e146":"6018",ccc49370:"6103","272dcb11":"6223","900689ba":"6463","43cd595a":"6585",db32d859:"6653",e8ce92a9:"6697","523ef08d":"7054",e42d6d1e:"7109","8fe94420":"7417","699bdc89":"7563","7c13eef8":"7983","6a809459":"8114","3c2f94fe":"8197","431d3c75":"8438","8aff9d8b":"8447","03675837":"8551","6875c492":"8610","234395f3":"8668","05504477":"8728","6165d255":"8908",c284bd0e:"9225",dbcbb24a:"9313",c5104875:"9331",cd4bffc0:"9364",a36ff0f2:"9399","00634dd8":"9428","1be78505":"9514","43b97ce7":"9520","1570240a":"9575"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,c)=>{var d=r.o(e,a)?e[a]:void 0;if(0!==d)if(d)c.push(d[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var f=new Promise(((c,f)=>d=e[a]=[c,f]));c.push(d[2]=f);var t=r.p+r.u(a),b=new Error;r.l(t,(c=>{if(r.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var f=c&&("load"===c.type?"missing":c.type),t=c&&c.target&&c.target.src;b.message="Loading chunk "+a+" failed.\n("+f+": "+t+")",b.name="ChunkLoadError",b.type=f,b.request=t,d[1](b)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,c)=>{var d,f,t=c[0],b=c[1],o=c[2],n=0;if(t.some((a=>0!==e[a]))){for(d in b)r.o(b,d)&&(r.m[d]=b[d]);if(o)var i=o(r)}for(a&&a(c);nArchive | Lido on Solana - +
    - + \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index d2011a26..3d9f5076 100644 --- a/blog/index.html +++ b/blog/index.html @@ -12,13 +12,13 @@ Blog | Lido on Solana - +

    · One min read

    Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!

    Delete the whole directory if you don't want the blog features. As simple as that!

    - + \ No newline at end of file diff --git a/blog/tags/index.html b/blog/tags/index.html index f7d3c826..2f73cd36 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -12,13 +12,13 @@ Tags | Lido on Solana - +

    Tags

    - + \ No newline at end of file diff --git a/blog/tags/lido/index.html b/blog/tags/lido/index.html index 9c9a0833..bbe0cae1 100644 --- a/blog/tags/lido/index.html +++ b/blog/tags/lido/index.html @@ -12,13 +12,13 @@ One post tagged with "lido" | Lido on Solana - +

    One post tagged with "lido"

    View All Tags

    · One min read

    Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!

    Delete the whole directory if you don't want the blog features. As simple as that!

    - + \ No newline at end of file diff --git a/blog/tags/solana/index.html b/blog/tags/solana/index.html index 6130f3be..16b73544 100644 --- a/blog/tags/solana/index.html +++ b/blog/tags/solana/index.html @@ -12,13 +12,13 @@ One post tagged with "solana" | Lido on Solana - +

    One post tagged with "solana"

    View All Tags

    · One min read

    Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!

    Delete the whole directory if you don't want the blog features. As simple as that!

    - + \ No newline at end of file diff --git a/blog/test/index.html b/blog/test/index.html index 10a86432..6c93eaad 100644 --- a/blog/test/index.html +++ b/blog/test/index.html @@ -12,13 +12,13 @@ test blog post | Lido on Solana - +

    test blog post

    · One min read

    Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!

    Delete the whole directory if you don't want the blog features. As simple as that!

    - + \ No newline at end of file diff --git a/deployments/index.html b/deployments/index.html index 38e14b3f..84d72ae9 100644 --- a/deployments/index.html +++ b/deployments/index.html @@ -12,7 +12,7 @@ Deployments | Lido on Solana - + @@ -24,7 +24,7 @@ know anyway.

    Mainnet-beta

    Configuration for v2:

    Solido version: v2.0.0(coming soon).

    {
    "cluster": "https://api.mainnet-beta.solana.com",

    "multisig_program_id": "AAHT26ecV3FEeFmL2gDZW6FfEqjPkghHbAkNZGqwT8Ww",
    "multisig_address": "3cXyJbjoAUNLpQsFrFJTTTp8GD3uPeabYbsCVobkQpD1",

    "solido_program_id": "CrX7kMhLC3cSsXJdT7JDgqrRVWGnUpX3gfEfxxU2NVLi",
    "solido_address": "49Yi1TKkNyYjPAFdR9LBvoHcUjuPX4Df5T5yv39w2XTn",
    "st_sol_mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj",

    "validator_list_address": "GL9kqRNUTUosW3RsDoXHCuXUZn73SgQQmBvtp1ng2co4",
    "maintainer_list_address": "5dvtr16i34hwXuCtTNHXXJ5ojeidVPXbceN9pXxrE8bn",
    "developer_fee_address": "5Y5LVTXbtMYsibjp9uQMmCyZbtSru8zktuxGPV9eHu3m",
    }

    Configuration for v1:

    Solido version: v1.0.1. Anker version: v1.3.0.

    {
    "cluster": "https://api.mainnet-beta.solana.com",

    "multisig_program_id": "AAHT26ecV3FEeFmL2gDZW6FfEqjPkghHbAkNZGqwT8Ww",
    "multisig_address": "3cXyJbjoAUNLpQsFrFJTTTp8GD3uPeabYbsCVobkQpD1",

    "solido_program_id": "CrX7kMhLC3cSsXJdT7JDgqrRVWGnUpX3gfEfxxU2NVLi",
    "solido_address": "49Yi1TKkNyYjPAFdR9LBvoHcUjuPX4Df5T5yv39w2XTn",

    "anker_program_id": "BNVB8pd4coHpY7MVcrtiHLCLst7fyDGzMtPmfJqFAhwj",
    "anker_address": "2kDSwqbzm2zJ2GzeS1uRXpRZFR8H9A9XhNFVcnG9sEUY"
    }
    AccountAddressDescription
    Multisig PDAGQ3QPrB1RHPRr4Reen772WrMZkHcFM4DL5q44x1BBTFmAddress that the multisig can sign on behalf of, used as the manager of the Solido instance, and upgrade authority of the Solido and Anker programs.
    stSOL Mint7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARjSPL token mint for stSOL, managed by Solido.
    bSOL MintEbMg3VYAE9Krhndw7FuogpHNcEPkXVhtXr7mGisdeaurSPL token mint for bSOL, managed by Anker.
    Stake AuthorityW1ZQRwUfSkDKy2oefRBUWph82Vr2zg9txWMA8RQazN5Stake and withdraw authority of stake accounts managed by Solido.
    Withdraw AuthorityGgrQiJ8s2pfHsfMbEFtNcejnzLegzZ16c9XtJ2X2FpuFWithdraw authority of vote accounts of Lido validators.
    Solido Reserve3Kwv3pEAuoe4WevPB4rgMBTZndGDb53XT7qwQKnvHPfXSolido’s reserve that holds deposited SOL until it is staked near the epoch boundary.
    Anker stSOL Reserve6emGaZGVvehtMNTr1mxhw9RNPptX6BVZVypTgbuq55GNHolds stSOL deposited into Anker.
    Anker UST ReserveBBuh4WDeS6GJTGdZvi2SYzZnmVJ1kZXRcudEcyuAXfUEHolds Anker's proceeds until they are sent to Terra.

    Multisig owners (including past owners):

    {
    "Cv6GM219kzMrdUUdgDGVJUPW6fGosvrhsFrvmEhz3Mc6": "P2P",
    "ENH1xvwjinUWkwEgw1hKduyAg7CrJMiKvr9nAS7wLHrp": "Staking Facilities",
    "6CawqfAJDviZGfUpHFJgeauq6H9vhKuivMMZULZeGnPw": "Figment",
    "AnoVUukL1fMAwEp4y2rrZV45BNHLes8ZwWsCRgEwhGH4": "ChainLayer",
    "6S21QCmpAadEhHj3pY2RMbPMGwgYNvS4Pd7zUXoRDMdK": "Chorus One",
    "DHLXnJdACTY83yKwnUkeoDjqi4QBbsYGa1v8tJL76ViX": "Mercurial",
    "8Lep9addZWUWqBNj3igx4QoHe43GBfvLhGJy18jJgWQa": "Solana Foundation"
    }

    Maintainers:

    {
    "p2pokvNcNc1SFCMoUrp1UBQ6SBET7H5EdLqahz4g55k": "P2P",
    "2rqLzNZCBWykEs8bFMbmgqCz4eosaEfU3aRL4RJWdZgQ": "Figment",
    "DqCZaFR6cTMvFMuz43HS77Zcz1quR93n11kT1yY6aVf4": "Staking Facilities",
    "AR7FaVeVvUQwnLtojZNUc42H987KiHqfc4AN1qEwPUJw": "Chorus One"
    }

    Testnet

    There is no official testnet or devnet deployment of a recent version of the Solido program. For testing, you can create your own instance instead.

    - + \ No newline at end of file diff --git a/development/building-docker-image/index.html b/development/building-docker-image/index.html index 721f0545..e450fdcd 100644 --- a/development/building-docker-image/index.html +++ b/development/building-docker-image/index.html @@ -12,13 +12,13 @@ dockerimage | Lido on Solana - +

    Buiding a Docker image locally

    In cases where there isn't a need to run the testnet (i.e. a local validator) and all that is required is the packaging of the Lido on Solana code and access to the Solana toolchain; there is the option of building a local container image.

    Prerequisites

    Building a local version of the container requires that you have Docker installed but also the Rust toolchain.

    Building

    To build the local image use the buildimage.sh script. This will build and package Lido on Solana along with the Solana toolchain into an image:

    chorusone/solido:hash

    Where hash will be the git hash of the current version of the code base.

    Running the container

    Once built, one can execute into the container interactively:

    docker run -it --rm chorusone/solido:hash /bin/sh

    This will provide a shell into the working directory where the Lido on Solana artefacts and the Solana toolchain are located. Inside the container, the Lido on Solana build artefacts are located in the solido directory which has the following structure:

    • /solido
      • /cli
      • /deploy

    The cli directory contains the solido cli artefacts. The deploy directory contains the artefacts for the on-chain programs for Lido on Solana.

    - + \ No newline at end of file diff --git a/development/index.html b/development/index.html index 2a545808..378a9f1a 100644 --- a/development/index.html +++ b/development/index.html @@ -12,13 +12,13 @@ development | Lido on Solana - +

    Development Overview

    Building the project

    The project can be built in either of two ways: in the supplied container or locally.

    Building the container image

    The building the docker image document gives detailed instructions on how to build and run the container supplied in the repo for testing and developing.

    Building locally

    In order to build Lido on Solana locally, one will need a number of prerequisites:

    • Rust toolchain
    • Solana toolchain
    • Misc System Packages: libudev-dev, libhidapi-dev, pkg-config, openssl (these are the package names for Debian, please source equivalents for your OS is they are not already installed)

    CLI

    To build/test the CLI, one can use the normal cargo commands:

    cargo build
    cargo test

    On-Chain Programs

    For the on-chain parts of the repo, one must use the bpf equivalent commands:

    cargo build-bpf
    cargo test-bpf

    Note: The BPF commands require the Solana SDK to be installed as was previously stated.

    Specification

    The Specification document is a deeper dive into the code of Lido on Solana to tour the intent and implementation of the on-chain program and the cli.

    - + \ No newline at end of file diff --git a/development/price-oracle/index.html b/development/price-oracle/index.html index 3526ac76..6a10487f 100644 --- a/development/price-oracle/index.html +++ b/development/price-oracle/index.html @@ -12,7 +12,7 @@ Price oracle | Lido on Solana - + @@ -38,7 +38,7 @@ Solido’s current exchange rate. You will need to run an instance of the maintenance daemon yourself to access these metrics; the endpoint is not intended to be exposed to the public internet.

    - + \ No newline at end of file diff --git a/development/reproducibility/index.html b/development/reproducibility/index.html index a066caff..101855be 100644 --- a/development/reproducibility/index.html +++ b/development/reproducibility/index.html @@ -12,7 +12,7 @@ Reproducibility | Lido on Solana - + @@ -30,7 +30,7 @@ room for future upgrades. The easiest way to verify, is to zero-pad our build of the program as well, so we can make a fair comparison. First, note the file size of the dumped program and of our build:

    $ stat onchain/lido.so build/lido.so
    File: onchain/lido.so
    Size: 1042528 Blocks: 2040 IO Block: 4096 regular file
    ...
    File: build/lido.so
    Size: 521264 Blocks: 1024 IO Block: 4096 regular file

    Confirm that the dump is larger than our build, then pad our build to that size:

    $ cp build/lido.so build/lido-padded.so
    $ truncate --size=1042528 build/lido-padded.so

    Now we can confirm that the programs match:

    $ sha256sum build/lido-padded.so onchain/lido.so
    350bae669da9b92ded86c0a89013160c42c4691d1cd5947a285b2e6657bb0c5b build/lido-padded.so
    350bae669da9b92ded86c0a89013160c42c4691d1cd5947a285b2e6657bb0c5b onchain/lido.so
    - + \ No newline at end of file diff --git a/development/specification/index.html b/development/specification/index.html index 1c322211..631fcd1d 100644 --- a/development/specification/index.html +++ b/development/specification/index.html @@ -12,13 +12,13 @@ specification | Lido on Solana - +

    Specification Overview

    The Solido repo can be generally split into three logical components:

    • solido (the on-chain program)
    • multisig (the on-chain multisig governance program)
    • cli (the command line interface into the solido and multisig programs)

    Caveat: The initial iterations of Solido used the Solana program library stake-pool program, whilst this is no longer used as a main component, there exists references to data structures within the stake pool program.

    There is also an dependency on the spl_token program from the Solana program library but this is used as is with no changes.

    - + \ No newline at end of file diff --git a/development/specification/solido/balance/index.html b/development/specification/solido/balance/index.html index 3127e9fc..bf1b0bf3 100644 --- a/development/specification/solido/balance/index.html +++ b/development/specification/solido/balance/index.html @@ -12,13 +12,13 @@ balance | Lido on Solana - +

    Balance

    The purpose of this module is to hold functionality that assists with calculating target balances associated with validators.

    Functions

    There are two functions within this module; one that is intended to get the ideal target balance for each validator and the second to get the validator that is the furthest below the ideal target balance along with its current balance.

    get_target_balance

    The intent of the get_target_balance function is to compare the current validator stake account balance to the ideal target balance of validators after any lamports that have not been delegated are taken into account. The balances of the active validators is then updated to the target balance in a uniform fashion. Any remainder due to rounding is also distributed.

    pub fn get_target_balance(
    undelegated_lamports: Lamports,
    validators: &Validators,
    target_balance: &mut [Lamports],
    ) -> Result<(), LidoError> {

    get_validator_furthest_below_target

    The intent of the get_validator_furthest_below_target function is to find the index and amount of the validator that is furthest from the ideal target balance.

    pub fn get_validator_furthest_below_target(
    validators: &Validators,
    target_balance: &[Lamports],
    ) -> (usize, Lamports) {
    - + \ No newline at end of file diff --git a/development/specification/solido/entrypoint/index.html b/development/specification/solido/entrypoint/index.html index c524e9e0..c79f37f5 100644 --- a/development/specification/solido/entrypoint/index.html +++ b/development/specification/solido/entrypoint/index.html @@ -12,13 +12,13 @@ entrypoint | Lido on Solana - +

    Entrypoint

    The only function in the entrypoint module is the entrypoint function. This module conforms to the standard Solana program structure and serves to call through to the process function in the process module; processor::process(program_id, accounts, instruction_data).

    entrypoint!(process_instruction);
    fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
    ) -> ProgramResult {
    - + \ No newline at end of file diff --git a/development/specification/solido/error/index.html b/development/specification/solido/error/index.html index a53411b2..4ed30606 100644 --- a/development/specification/solido/error/index.html +++ b/development/specification/solido/error/index.html @@ -12,13 +12,13 @@ error | Lido on Solana - +

    Error

    The error module defines the LidoError enum for the available error types in the Solido program along with some small conversion implementations to and from the Solana ProgramError struct.

    Errors

    The LidoError enum, at time of writing, defines the following errors:

    ErrorDescription
    AlreadyInUseThe Lido address passed to the program is in use; i.e. the Solido program has already been initialised.
    InvalidOwnerThe address of the owner of the Solido program is different to the passed program id.
    InvalidAmountThe amount being staked is below the minimum stake amount.
    SignatureMissingA required signature is missing
    InvalidReserveAuthorityThe authority for the reserve account, where SOL gets deposited, is invalid
    CalculationFailureCalculation failed due to division by zero or overflow
    WrongStakeStateStake account is in an invalid state or does not exist when processing a stake deposit
    MaximumNumberOfAccountsExceededThe maximum number of entries in the account map is already at maximum capacity as defined by maximum entries
    UnexpectedMaxValidatorsThe size of the account for the Solido state does not match max_validators
    InvalidManagerWrong manager trying to alter the state of the Solido program
    InvalidMaintainerWrong maintainer trying to alter the state of the Solido program
    InvalidAccountInfoThe provided account is mismatched in is_writable or is_signer to what was expected for that type of account
    TooManyAccountKeysMore accounts were provided than Solido expects
    InvalidValidatorCreditAccountThe account provided when claiming validator fees is incorrect
    InvalidFeeRecipientThe provided fee recipient account is incorrect
    DuplicatedEntryThe entry trying to be added to the account_map already exists
    ValidatorHasUnclaimedCreditThe validator trying to be removed has unclaimed credit, the credit should be minted before the validator is removed
    ReserveIsNotRentExemptThe reserve account value is not above the minimum value for rent exemption
    AmountExceedsReserveThe requested amount for reserve withdrawal exceeds the maximum held in the reserve account when considering rent exemption
    InvalidAccountMemberAn entry in the account map is not present
    InvalidLidoSizeLido has an invalid size, calculated with the Lido's constant size plus required to hold variable structures
    NoActiveValidatorsThere are no validators with an active stake account to delegate to
    InvalidStakeAccountWhen staking part of the reserve to a new stake account, the next program-derived address for the stake account associated with the given validator, does not match the provided stake account
    InvalidStSolAccountWe expected an SPL token account that holds stSOL, but this was not an SPL token account, or its mint did not match
    - + \ No newline at end of file diff --git a/development/specification/solido/index.html b/development/specification/solido/index.html index 371e7398..b0f1d925 100644 --- a/development/specification/solido/index.html +++ b/development/specification/solido/index.html @@ -12,13 +12,13 @@ solido | Lido on Solana - +

    Solido

    Solido is the core on-chain program (aside from the multisig governance program) for Lido on Solana.

    Program Structure

    The program structure follows the recommended structure for Solana programs.

    • src
      • lib.rs -> to register modules
      • entrypoint.rs -> initial entrypoint into the program
      • instruction.rs -> program api and the (de)serializing of instruction related data
      • processor.rs -> program logic
      • state.rs -> program objects/structures and the (de)serializing of program state
      • error.rs -> error objects specific to the program
      • ...

    Solido has a couple of additional modules for specific behaviour or domain functionality:

    • src
      • ...
      • account_map.rs -> objects to assist with mapping objects to a PubKey as key value pair
      • balance.rs -> functionality related to target balances associated with validators
      • logic.rs -> logic and helper functions associated with the program
      • process_management.rs -> functionality associated with changing the state of the program
      • token.rs -> types to make working with token balances safer

    The solido specification documents will go into detail for each of these modules to describe the structure and intent of the affiliated code.

    Terminology

    • Lamport: The minimum unit of denomination in Solana, which an equivalent value of 0.000000001 SOL. A helper struct,Lamports , is used in Solido to ensure safety when dealing with balances.
    • StLamport: The minimum unit of denomination in Solido pool tokens, stSOL, which an equivalent value of 0.000000001 stSOL. A helper struct,StLamports , is used in Solido to ensure safety when dealing with balances.

    Additional Solana specific terminology can be found here.

    - + \ No newline at end of file diff --git a/development/specification/solido/instruction/index.html b/development/specification/solido/instruction/index.html index 6ec4fb5d..1e29e74e 100644 --- a/development/specification/solido/instruction/index.html +++ b/development/specification/solido/instruction/index.html @@ -12,14 +12,14 @@ instruction | Lido on Solana - +

    Instruction

    The purpose of the instruction module is to contain all functionality and structures related to the Solido program instructions.

    Enums

    Lido Instruction

    The Lido instruction enum contains all the possible instructions for the Solido program.

    Initialize

    Initialize {
    fee_distribution: FeeDistribution,
    max_validators: u32,
    max_maintainers: u32,
    },

    The initialise instruction should be passed an appropriate FeeDistribution along with the maximum number of validators and maintainers the instance of Solido will support.

    Deposit

    Deposit {
    amount: Lamports,
    },

    The instruction to deposit an amount defined using the helper struct Lamports

    StakeDeposit

    StakeDeposit {
    amount: Lamports,
    },

    The StakeDeposit instruction moves deposits, specified in Lamports, into a new stake account and delegates it to a member validator.

    Withdraw

    Withdraw  {
    amount: Lamports,
    },

    The Withdraw instruction withdraws an amount, specified in Lamports, from the Solido program.

    Note: Withdraws are not currently supported in the Solido program but will be implemeted in a future version.

    DistributeFees

    DistributeFees

    The DistributeFees instruction will calculate any fees due to the Lido stakeholders, allocate the fees to the program accounts and update the validator fees to be claimed when the ClaimValidatorFees instruction is called.

    Note: Only a maintainer can call this instruction

    ClaimValidatorFees

    ClaimValidatorFees

    The ClaimValidatorFees instruction will mint any unclaimed fees to the validator's fee account.

    ChangeFeeSpec

    ChangeFeeSpec {
    new_fee_distribution: FeeDistribution,
    },

    The ChangeFeeSpec instruction changes the fee distribution ratios after initialisation when given an appropriate new FeeDistribution.

    AddValidator

    AddValidator,

    The AddValidator instruction add a given validator to the pool of validators.

    Note: Only the manager role can call this instruction.

    RemoveValidator

    RemoveValidator,

    The RemoveValidator instruction removes a given validator from the pool of validators. This instruction will fail with an ValidatorHasUnclaimedCredit error if the validator still has unclaimed credit.

    Note: Only the manager role can call this instruction.

    AddMaintainer

    AddMaintainer,

    The AddMaintainer instruction add a given maintainer to the pool of maintainers.

    Note: Only the manager role can call this instruction.

    RemoveMaintainer

    RemoveMaintainer,

    Note: Only the manager role can call this instruction.

    Macros

    Accounts Struct and Accounts Struct Meta

    macro_rules! accounts_struct {
    ...
    }
    macro_rules! accounts_struct_meta {
    ...
    }

    The accounts_struct and accounts_struct_meta macros assist in generating two structs for passing accounts by name. This has the following advantages over dealing with a list of accounts manually:

    • There is no risk of making a mistake in the ordering of accounts, or forgetting to update one place after modifying a different place.
    • For every account, it forces consideration of if that account should be writable or not.
    • It has a shorthand for defining accounts that have a statically known address.

    Example:


    accounts_struct! {
    ExampleAccountsMeta, ExampleAccountsInfo {
    frobnicator: { is_signer: true, is_writable: false },
    sysvar_rent = sysvar::rent::id(),
    }
    ...
    }

    This will generate two structs of the form:

    struct ExampleAccountsMeta {
    frobnicator: Pubkey,
    }

    impl ExampleAccountsMeta {
    pub fn to_vec(&self) -> Vec<AccountMeta>;
    }

    struct ExampleAccountsInfo<'a> {
    frobnicator: &'a AccountInfo<'a>,
    sysvar_rent: &'a AccountInfo<'a>,
    }

    impl ExampleAccountsInfo {
    pub fn try_from_slice<'a, 'b: 'a>(raw: &'b [AccountInfo<'a>]) -> Result<ExampleAccountsInfo, ProgramError>;
    }

    The generated structs ensure that the accounts returned by to_vec are in the same order that try_from_slice expects them. try_from_slice additionally validates that is_signer and is_writable match the definition.

    Accounts

    The accounts used by Solido are generated using the accounts_struct macro. They are summarized here, for each instruction, along with the signable and writable status.

    InitializeAccounts

    Generated structs => InitializeAccountsMeta and InitializeAccountsInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    managerfalsefalse
    st_sol_mintfalsefalse
    treasury_accountfalsefalse
    developer_accountfalsefalse
    reserve_accountfalsefalse

    Constants included:

    const sysvar_rent = sysvar::rent::id(),
    const spl_token = spl_token::id(),

    DepositAccounts

    Generated structs => DepositAccountsMeta and DepositAccountsInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    usertruetrue
    recipientfalsetrue
    st_sol_mintfalsetrue
    reserve_accountfalsetrue

    Constants included:

    const spl_token = spl_token::id(),
    const system_program = system_program::id(),
    const sysvar_rent = sysvar::rent::id(),

    StakeDepositAccount

    Generated structs => StakeDepositAccountMeta and StakeDepositAccountInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    maintainertruefalse
    reservefalsetrue
    validator_vote_accountfalsefalse
    stake_account_endfalsetrue
    deposit_authorityfalsetrue

    Constants included:

    const sysvar_clock = sysvar::clock::id(),
    const system_program = system_program::id(),
    const sysvar_rent = sysvar::rent::id(),
    const stake_program = stake_program::id(),
    const stake_history = stake_history::id(),
    const stake_program_config = stake_program::config_id(),

    ChangeFeeSpec

    Generated structs => ChangeFeeSpecMeta and ChangeFeeSpecInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    managertruefalse
    treasury_accountfalsefalse
    developer_accountfalsefalse

    No additonal constants.

    AddValidator

    Generated structs => AddValidatorMeta and AddValidatorInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    managertruefalse
    validator_vote_accountfalsefalse
    validator_fee_st_sol_accountfalsefalse

    Constants included:

    const sysvar_clock = sysvar::clock::id(),
    const sysvar_stake_history = sysvar::stake_history::id(),
    const sysvar_stake_program = stake_program::id(),

    RemoveValidator

    Generated structs => RemoveValidatorMeta and RemoveValidatorInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    managertruefalse
    validator_vote_account_to_removefalsefalse

    Constants included:

    const sysvar_clock = sysvar::clock::id(),
    const sysvar_stake_program = stake_program::id(),

    DistributeFees

    Generated structs => DistributeFeesMeta and DistributeFeesInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    maintainertruefalse
    st_sol_mintfalsetrue
    reserve_authorityfalsefalse
    treasury_accountfalsetrue
    developer_accountfalsetrue

    Constants included:

    const spl_token = spl_token::id(),

    ClaimValidatorFees

    Generated structs => ClaimValidatorFeesMeta and DistributeFeesInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    st_sol_mintfalsetrue
    reserve_authorityfalsefalse
    validator_fee_st_sol_accountfalsetrue

    Constants included:

    const spl_token = spl_token::id(),

    AddMaintainer

    Generated structs => AddMaintainerMeta and AddMaintainerInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    managertruefalse
    maintainerfalsefalse

    No additonal constants.

    RemoveMaintainer

    Generated structs => RemoveMaintainerMeta and RemoveMaintainerInfo

    Account NamePurposeis_signeris_writable
    lidofalsetrue
    managertruefalse
    maintainerfalsefalse

    No additonal constants.

    Functions

    For each of the instructions (and their associated account structs) the module contains the functions required to generate the appropriate instructions.

    Each of the functions return a result object of the appropriate instruction or a ProgramError:

    -> Result<Instruction, ProgramError>

    initialise

    Constructs, verifies the accounts and returns the Lido::Initialize instruction.

    pub fn initialize(
    program_id: &Pubkey,
    fee_distribution: FeeDistribution,
    max_validators: u32,
    max_maintainers: u32,
    accounts: &InitializeAccountsMeta,
    ) -> Result<Instruction, ProgramError> {

    deposit

    Constructs, verifies the accounts and returns the Lido::Deposit instruction.

    pub fn deposit(
    program_id: &Pubkey,
    accounts: &DepositAccountsMeta,
    amount: Lamports,
    ) -> Result<Instruction, ProgramError> {

    stake_deposit

    Constructs, verifies the accounts and returns the Lido::StakeDeposit instruction.

    pub fn stake_deposit(
    program_id: &Pubkey,
    accounts: &StakeDepositAccountsMeta,
    amount: Lamports,
    ) -> Result<Instruction, ProgramError> {

    change_fee_distribution

    Constructs, verifies the accounts and returns the Lido::ChangeFeeSpec instruction.

    pub fn change_fee_distribution(
    program_id: &Pubkey,
    new_fee_distribution: FeeDistribution,
    accounts: &ChangeFeeSpecMeta,
    ) -> Result<Instruction, ProgramError> {

    add_validator

    Constructs, verifies the accounts and returns the Lido::AddValidator instruction.

    pub fn add_validator(
    program_id: &Pubkey,
    accounts: &AddValidatorMeta,
    ) -> Result<Instruction, ProgramError> {

    remove_validator

    Constructs, verifies the accounts and returns the Lido::RemoveValidator instruction.

    pub fn remove_validator(
    program_id: &Pubkey,
    accounts: &RemoveValidatorMeta,
    ) -> Result<Instruction, ProgramError> {

    distribute_fees

    Constructs, verifies the accounts and returns the Lido::DistributeFees instruction.

    pub fn distribute_fees(
    program_id: &Pubkey,
    accounts: &DistributeFeesMeta,
    ) -> Result<Instruction, ProgramError> {

    claim_validator_fees

    Constructs, verifies the accounts and returns the Lido::ClaimValidatorFees instruction.

    pub fn claim_validator_fees(
    program_id: &Pubkey,
    accounts: &ClaimValidatorFeeMeta,
    ) -> Result<Instruction, ProgramError> {

    add_maintainer

    Constructs, verifies the accounts and returns the Lido::AddMaintainer instruction.

    pub fn add_maintainer(
    program_id: &Pubkey,
    accounts: &AddMaintainerMeta,
    ) -> Result<Instruction, ProgramError> {

    remove_maintainer

    Constructs, verifies the accounts and returns the Lido::RemoveMaintainer instruction.

    pub fn remove_maintainer(
    program_id: &Pubkey,
    accounts: &RemoveMaintainerMeta,
    ) -> Result<Instruction, ProgramError> {
    - + \ No newline at end of file diff --git a/development/specification/solido/lib/index.html b/development/specification/solido/lib/index.html index 6ca2f73d..92475808 100644 --- a/development/specification/solido/lib/index.html +++ b/development/specification/solido/lib/index.html @@ -12,13 +12,13 @@ lib | Lido on Solana - +

    Lib

    Aside from the standard Rust convention of pulling all the modules together, the lib.rs module contains some important seeds for the Solido program along with functionality to find the correct public key and bump seed for a given authority.

    Constants

    RESERVE_AUTHORITY

    Seed for reserve authority in SOL.

    pub const RESERVE_AUTHORITY: &[u8] = b"reserve_authority";

    DEPOSIT_AUTHORITY

    Seed for deposit authority

    pub const DEPOSIT_AUTHORITY: &[u8] = b"deposit_authority";

    VALIDATOR_STAKE_ACCOUNT

    Additional seed for validator stake accounts.

    pub const VALIDATOR_STAKE_ACCOUNT: &[u8] = b"validator_stake_account";

    Functions

    find_authority_program_address

    The find_authority_program_address function finds the public key and bump seed for a given authority.

    pub fn find_authority_program_address(
    program_id: &Pubkey,
    lido_address: &Pubkey,
    authority: &[u8],
    ) -> (Pubkey, u8) {

    Note: This function can take some time to run so it is preferred to use PubKey::create_program_address function inside programs.

    - + \ No newline at end of file diff --git a/development/specification/solido/logic/index.html b/development/specification/solido/logic/index.html index ca9afa34..d9acd406 100644 --- a/development/specification/solido/logic/index.html +++ b/development/specification/solido/logic/index.html @@ -12,13 +12,13 @@ logic | Lido on Solana - +

    Logic

    The logic module contains general program logic that is not more directly associated with process, state or token functionality.

    Functions

    check_rent_exempt

    This function checks the balance of account in lamports, along with the data length to determine if the account is rent exempt.

    pub(crate) fn check_rent_exempt(
    rent: &Rent,
    account_info: &AccountInfo,
    account_name: &'static str,
    ) -> Result<(), ProgramError> {

    get_reserve_available_amount

    This function gets the amount of lamports in reserve. The rent is subtracted from the total amount.

    pub fn get_reserve_available_amount(
    reserve_account: &AccountInfo,
    sysvar_rent: &Rent,
    ) -> Result<Lamports, LidoError> {

    Note: this function will fail if the reserve's balance minus rent is < 0.

    calc_total_lamports

    Calculates the sum of lamports available in the reserve (after rent us discounted) and the stake pool

    pub fn calc_total_lamports(
    lido: &Lido,
    reserve_account: &AccountInfo,
    sysvar_rent: &Rent,
    ) -> Result<Lamports, LidoError> {

    token_mint_to

    Creates and issues a spl_token MintTo instructioni from the Solana SPL token library program.

    pub fn token_mint_to<'a>(
    lido: &Pubkey,
    token_program: AccountInfo<'a>,
    mint: AccountInfo<'a>,
    destination: AccountInfo<'a>,
    authority: AccountInfo<'a>,
    authority_type: &[u8],
    bump_seed: u8,
    amount: StLamports,
    ) -> Result<(), ProgramError> {

    deserialize_lido

    This function first checks the the lido account is indeed the owner and then deserializes the lido data into the Lido struct.

    pub fn deserialize_lido(program_id: &Pubkey, lido: &AccountInfo) -> Result<Lido, ProgramError>
    - + \ No newline at end of file diff --git a/development/specification/solido/process_management/index.html b/development/specification/solido/process_management/index.html index f7040c0e..eed56ef3 100644 --- a/development/specification/solido/process_management/index.html +++ b/development/specification/solido/process_management/index.html @@ -12,13 +12,13 @@ process_management | Lido on Solana - +

    Process Management

    Process management contains functionality that changes the state of Solido.

    Functions

    process_change_fee_spec

    This function changes the fee spec in the Solido state.

    pub fn process_change_fee_spec(
    program_id: &Pubkey,
    new_fee_distribution: FeeDistribution,
    accounts_raw: &[AccountInfo],
    ) -> ProgramResult {

    The function is gated so that only the manager role can call the function successfully. It additionally checks that the developer and treasury accounts passed to the function are stSOL accounts.

    Note: This function can also be used to change the keys associated with the developer and treasury accounts in addition to changing the fee spec.

    process_add_validator

    This function add a validator to the list of validators in the Solido state.

    pub fn process_add_validator(program_id: &Pubkey, accounts_raw: &[AccountInfo]) -> ProgramResult {

    The add validator process is gated so that only the manager role can call the function successfully. It additionally checks that the validator fee account is an stSOL accounts.

    process_remove_validator

    This function remove a validator from the list of validators in the Solido state.

    pub fn process_remove_validator(program_id: &Pubkey, accounts_raw: &[AccountInfo]) -> ProgramResult {

    The remove validator process is gated so that only the manager role can call the function successfully. Additionally, before a validator can be removed, all fees must be claimed. The function will fail with ValidatorHAsUnclaimedCredit error if there are unclaimed fees.

    process_claim_validator_fee

    For a given validator fee account, this function will mint stSOL to the fee account equal to any outstanding fees due. Once minting is complete, the fee amount for the validator is reset to 0.

    pub fn process_claim_validator_fee(
    program_id: &Pubkey,
    accounts_raw: &[AccountInfo],
    ) -> ProgramResult {

    This function is not gated so anyone can call it successfully.

    process_distribute_fees

    This function calculates the correct Fee Distribution and mints the appropriate stSOL tokens to the treasury and developer accounts. Once minting is complete, the function sets the validator fees attributable to the validators in the Solido state ready for the process_claim_validator_fee to be called at a subsequent point in time.

    pub fn process_distribute_fees(program_id: &Pubkey, accounts_raw: &[AccountInfo]) -> ProgramResult {

    This function is gated so that only the maintainer role can call it successfully.

    process_add_maintainer

    This function adds a maintainer to the list of maintainers in the Solido state.

    pub fn process_add_maintainer(program_id: &Pubkey, accounts_raw: &[AccountInfo]) -> ProgramResult {

    This function is gated so that only the manager role can call it successfully.

    process_remove_maintainer

    This function removes a maintainer from the list of maintainers in the Solido state.

    pub fn process_remove_maintainer(program_id: &Pubkey, accounts_raw: &[AccountInfo]) -> ProgramResult {

    This function is gated so that only the manager role can call it successfully.

    - + \ No newline at end of file diff --git a/development/specification/solido/processor/index.html b/development/specification/solido/processor/index.html index 5a112730..9ce39729 100644 --- a/development/specification/solido/processor/index.html +++ b/development/specification/solido/processor/index.html @@ -12,13 +12,13 @@ process | Lido on Solana - +

    Process

    Following the Solana convention, this module contains the processing logic of the on-chain program.

    Functions

    process_initialize

    This is the function that initializes the state of Solido.

    pub fn process_initialize(
    version: u8,
    program_id: &Pubkey,
    fee_distribution: FeeDistribution,
    max_validators: u32,
    max_maintainers: u32,
    accounts_raw: &[AccountInfo],
    ) -> ProgramResult {

    This function completes a number of checks:

    • confirms the Solido account is rent exempt
    • confirms the reserve account is rent exempt
    • checks that the size of the Solido data is the same as expected given the constraints of max_maintainers, max_validators and LIDO_CONSTANT_SIZE

    Once those checks are complete the function then finds the bump seeds associated with the RESERVE_AUTHORITY and DEPOSIT_AUTHORITY for the defined constants, constructs the fee spec, checks that the treasury_account and developer_account are valid stSOL accounts and finally then builds and serializes the state of Solido.

    process_deposit

    This function is responsible for taking SOL deposits and minting the equivalent stSOL to the depositors receiving account.

    pub fn process_deposit(
    program_id: &Pubkey,
    amount: Lamports,
    accounts_raw: &[AccountInfo],
    ) -> ProgramResult {

    The recipient account must be capable of holding stSOL. The deposit is transferred from the users account to the reserve account and, after checking the correct amount of equivalent stSOL, these are minted to the recipient account. The total stSOL shares is updated and the new Solido state is serialized.

    process_stake_deposit

    The process stake deposit function is responsible for creating validator stake account and delegating reserve funds to those accounts.

    pub fn process_stake_deposit(
    program_id: &Pubkey,
    amount: Lamports,
    raw_accounts: &[AccountInfo],
    ) -> ProgramResult {

    This function is gated so that only those in a maintainer role can run it successfully. The function must check that the following are true:

    • the amount being staked is greater than the minimum stake balance
    • the amount being staked is less then the available reserve balance

    Once those checks have been passed the function will try to find a stake address associated to the given validator and confirm that the account is uninitialized. The account is then allocated, assigned, the given amount is transferred to the account from the reserve. The account is then initialized and the amount is then delegated to the validator. Finally the validator stake amount is updated in the Solido state and the state is then serialized.

    process_withdraw

    This function processes a withdrawal.

    Note: Withdrawals are currently not supported in Solido; they will be added in a subsequent version.

    pub fn process_withdraw(
    _program_id: &Pubkey,
    _pool_tokens: StLamports,
    _accounts: &[AccountInfo],
    ) -> ProgramResult {

    process

    This is the main process function that is called from the entrypoint.

    pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {

    The function simply parses the instruction passed and calls the appropriate processing logic.

    - + \ No newline at end of file diff --git a/development/specification/solido/state/index.html b/development/specification/solido/state/index.html index dbab92c3..1cf15be4 100644 --- a/development/specification/solido/state/index.html +++ b/development/specification/solido/state/index.html @@ -12,14 +12,14 @@ state | Lido on Solana - +

    State

    Constants

    LIDO_VERSION

    This byte specifies the version of the Solido state.

    pub const LIDO_VERSION: u8 = 0;

    LIDO_CONSTANT_HEADER_SIZE

    This defines the size of the header of the Solido state.

    pub const LIDO_CONSTANT_HEADER_SIZE: usize = 1 + 2 * 32 + 8 + 2;

    The header size should be equivalent to the following:

    • the size of the version byte
    • the size of the manager and st_sol_mint public keys
    • the size of the st_sol_total_shares which is an stLamports struct
    • the size of the sol_reserve_authority_bump_seed and the deposit_authority_bump_seed

    LIDO_CONSTANT_FEE_SIZE

    This defines the size of the fee section of the Lido state.

    pub const LIDO_CONSTANT_FEE_SIZE: usize = 2 * 32 + 3 * 4;

    This should be equivalent to the following:

    • the size of the FeeDistribution struct
    • the size of the FeeRecipients struct

    Types

    Validators

    The validators type uses the AccountMap struct and the Validator struct to create a helper type to assist in dealing with the collection of validators needed for the Soldio state.

    pub type Validators = AccountMap<Validator>;

    Maintainers

    The Maintainers type leverages a type alias, AccountSet, for an AccountMap with a unit type.

    pub type Maintainers = AccountSet;

    Structs

    Lido

    This is the main structure for maintaining the Solido state.

    pub struct Lido {
    pub lido_version: u8,
    pub manager: Pubkey,
    pub st_sol_mint: Pubkey,
    pub st_sol_total_shares: StLamports,
    pub sol_reserve_authority_bump_seed: u8,
    pub deposit_authority_bump_seed: u8,
    pub fee_distribution: FeeDistribution,
    pub fee_recipients: FeeRecipients,
    pub validators: Validators,
    pub maintainers: Maintainers,
    }

    Implemented functions on Lido

    calculate_size

    This function calculates the size of the Solido state if it had the maximum number of validators and maintainers.

    pub fn calculate_size(max_validators: u32, max_maintainers: u32) -> usize {
    calc_pool_tokens_for_deposit

    This function calculates the correct amount of pool tokens, stSOL, for a given stake deposit in SOL.

    equivalent pool token (stLamports)=stake equivalent in stLamportsTotal Shares stLamportsTotal Lamports\textnormal{equivalent pool token (stLamports)}=\textnormal{stake equivalent in stLamports}*\frac{\textnormal{Total Shares stLamports}}{\textnormal{Total Lamports}}
    pub fn calc_pool_tokens_for_deposit(
    &self,
    stake_lamports: Lamports,
    total_lamports: Lamports,
    ) -> Option<StLamports> {
    is_initialized

    Checks if the instance of Solido has already been initialized.

    pub fn is_initialized(&self) -> ProgramResult {
    check_mint_is_st_sol_mint

    Confirms that the passed mint account is indeed Solido's expected stSOL mint.

    pub fn check_mint_is_st_sol_mint(&self, mint_account_info: &AccountInfo) -> ProgramResult {
    check_is_st_sol_account

    Confirms that the given account is an SPL token account with our stSOL mint as mint.

    pub fn check_is_st_sol_account(&self, token_account_info: &AccountInfo) -> ProgramResult {
    check_manager

    Checks if the passed manager is the same as the one stored in the state

    pub fn check_manager(&self, manager: &AccountInfo) -> ProgramResult {
    check_maintainer

    Checks if the passed maintainer belong to the list of maintainers

    pub fn check_maintainer(&self, maintainer: &AccountInfo) -> ProgramResult {
    get_reserve_account

    This function returns the address of the reserve account, i.e. the account where SOL gets deposited to.

    pub fn get_reserve_account(
    &self,
    program_id: &Pubkey,
    solido_address: &Pubkey,
    ) -> Result<Pubkey, ProgramError> {
    check_reserve_authority

    Confirms that the reserve authority passed does in fact belong to this Solido instance.

    pub fn check_reserve_authority(
    &self,
    program_id: &Pubkey,
    solido_address: &Pubkey,
    reserve_authority_info: &AccountInfo,
    ) -> Result<Pubkey, ProgramError> {

    Validator

    The validator struct maintains the data regarding each validator that is required to generate staking accounts and maintain the fees due.

    pub struct Validator {
    pub fee_credit: StLamports,
    pub fee_address: Pubkey,
    pub stake_accounts_seed_begin: u64,
    pub stake_accounts_seed_end: u64,
    pub stake_accounts_balance: Lamports,
    }

    Implemented functions on Validator

    find_stake_account_address

    This function finds a stake account associated with a given validator vote account.

    pub fn find_stake_account_address(
    program_id: &Pubkey,
    solido_account: &Pubkey,
    validator_vote_account: &Pubkey,
    seed: u64,
    ) -> (Pubkey, u8) {

    This function wraps the Solana Pubkey::find_program_address. That function tries to find a valid program address and its corresponding bump seed which must be passed as an additional seed when calling invoke_signed. The processes of finding a valid program address is by trial and error,and even though it is deterministic given a set of inputs it can take a variable amount of time to succeed across different inputs. This means that when called from an on-chain program it may incur a variable amount of the program's compute budget. Programs that are meant to be very performant may not want to use this function because it could take a considerable amount of time. Also, programs that area already at risk of exceeding their compute budget should also call this with care since there is a chance that the program's budget may be occasionally exceeded.

    Additional Note: The underlying Solana program function will panic in the very unlikely event that the additional seed could not be found.

    FeeDistribution

    The FeeDistribution struct simply maintains the ratios of distribution between the treasury, developer (Lido team), and the validators.

    pub struct FeeDistribution {
    pub treasury_fee: u32,
    pub validation_fee: u32,
    pub developer_fee: u32,
    }

    FeeRecipients

    The FeeRecipients struct is another simple struct that holds the Pubkey addresses of the treasury and developer (Lido team) accounts that will receive fees.

    pub struct FeeRecipients {
    pub treasury_account: Pubkey,
    pub developer_account: Pubkey,
    }
    - + \ No newline at end of file diff --git a/development/specification/solido/token/index.html b/development/specification/solido/token/index.html index f88763f4..433e9040 100644 --- a/development/specification/solido/token/index.html +++ b/development/specification/solido/token/index.html @@ -12,13 +12,13 @@ token | Lido on Solana - + - + \ No newline at end of file diff --git a/fees/index.html b/fees/index.html index 06c60676..04ff8317 100644 --- a/fees/index.html +++ b/fees/index.html @@ -12,7 +12,7 @@ Fees | Lido on Solana - + @@ -27,7 +27,7 @@ multisig when called for by the Lido DAO. The fee percentages are stored on-chain, and you can inspect the current values with solido show-solido.

    - + \ No newline at end of file diff --git a/frontend-integration/manual-instructions/index.html b/frontend-integration/manual-instructions/index.html index 66a33f5e..b1a92267 100644 --- a/frontend-integration/manual-instructions/index.html +++ b/frontend-integration/manual-instructions/index.html @@ -12,7 +12,7 @@ Migration Guide (v1 → v2) | Lido on Solana - + @@ -20,7 +20,7 @@

    Migration Guide (v1 → v2)

    caution

    Our smart-contract (solido) upgrade is done. It brought breaking changes to frontend integration, that's why it's critical important to update instructions, because v1 instructions are not working anymore. But the best is to start using SDK, where is already supported v2.

    Solido Changes:

    • Validators and Maintainers list now is stored in a separate account, you need to fetch them separately, in first version they were stored inside protocol state.
    • Validator structure was changed:
      • pubkey now is stored in vote_account_address
      • was removed fee_credit, fee_address fields
    • Withdraw instruction fields:
      • Changed buffer layout, had been added validator_index
      • Instruction code was 2, now is 23 due to technical peculiarity
      • validator_list had been added to instructions keys

    1. Validators list now is stored in a separate account

    - ['validators', Validators] // Validator scheme
    + ['validator_list', [32]] // PublicKey

    That's why, in order to get validator list you need to fetch additionally them after fetching solido state:

    const deserializedAccountInfo = deserializeUnchecked(
    accountInfoschema,
    Lido,
    accountInfo.data,
    );

    const validatorsList = new PublicKey(deserializedAccountInfo.validators_list);
    const validators = await connection.getAccountInfo(validatorsList);

    const deserializedValidators = deserializeUnchecked(
    validatorsSchema,
    AccountList,
    validators.data,
    );

    // here is parsed validator list array
    console.log('validators', deserializedValidators.entries);

    Also changed structure of validator.

    V1:

    // accountInfoScheme
    [
    // ... other fields
    [
    SeedRange,
    {
    kind: 'struct',
    fields: [
    ['begin', 'u64'],
    ['end', 'u64'],
    ],
    },
    ],
    [
    ValidatorClass,
    {
    kind: 'struct',
    fields: [
    ['fee_credit', 'u64'],
    ['fee_address', [32]],
    ['stake_seeds', SeedRange],
    ['unstake_seeds', SeedRange],
    ['stake_accounts_balance', 'u64'],
    ['unstake_accounts_balance', 'u64'],
    ['active', 'u8'],
    ],
    },
    ],
    [
    PubKeyAndEntry,
    {
    kind: 'struct',
    fields: [
    ['pubkey', [32]],
    ['entry', ValidatorClass],
    ],
    },
    ],
    [
    Validators,
    {
    kind: 'struct',
    fields: [
    ['entries', [PubKeyAndEntry]],
    ['maximum_entries', 'u32'],
    ],
    },
    ]
    ]

    V2:

    const validatorsSchema = new Map([
    [
    ListHeader,
    {
    kind: 'struct',
    fields: [
    ['account_type', 'u8'],
    ['lido_version', 'u8'],
    ['max_entries', 'u32'],
    ],
    },
    ],
    [
    SeedRange,
    {
    kind: 'struct',
    fields: [
    ['begin', 'u64'],
    ['end', 'u64'],
    ],
    },
    ],
    [
    ValidatorClass,
    {
    kind: 'struct',
    fields: [
    ['vote_account_address', [32]],
    ['stake_seeds', SeedRange],
    ['unstake_seeds', SeedRange],
    ['stake_accounts_balance', 'u64'],
    ['unstake_accounts_balance', 'u64'],
    ['effective_stake_balance', 'u64'],
    ['active', 'u8'],
    ],
    },
    ],
    [
    AccountList,
    {
    kind: 'struct',
    fields: [
    ['header', ListHeader],
    ['entries', [ValidatorClass]],
    ],
    },
    ],
    ]);
    Typings:

    V1:

    type Validator = {
    entry: {
    vote_account_address: PublicKey;
    stake_seeds: SeedRange;
    unstake_seeds: SeedRange;
    stake_accounts_balance: BN;
    unstake_accounts_balance: BN;
    effective_stake_balance: BN;
    active: boolean;
    };
    pubkey: PublicKey;
    };

    type AccountInfo = {
    // other fields
    validators: {
    entries: Validator[];
    };
    };

    V2:

    type Validator = {
    vote_account_address: PublicKey;
    stake_seeds: SeedRange;
    unstake_seeds: SeedRange;
    stake_accounts_balance: BN;
    unstake_accounts_balance: BN;
    effective_stake_balance: BN;
    active: boolean;
    };

    type ValidatorsList = {
    header: ListHeader;
    entries: Validator[];
    };

    2. Withdraw Instruction

    • Changed buffer layout, had been added validator_index:

    V1:

    import { nu64, struct, u8 } from 'buffer-layout';

    const dataLayout = struct([u8('instruction'), nu64('amount')]);

    const data = Buffer.alloc(dataLayout.span);

    V2:

    import { nu64, struct, u32, u8 } from 'buffer-layout';

    const dataLayout = struct([u8('instruction'), nu64('amount'), u32('validator_index')]);

    const data = Buffer.alloc(dataLayout.span);
    • Instruction code:

    V1:

    dataLayout.encode(
    {
    instruction: 2, // old code of withdraw instruction
    amount: new BN(amount),
    },
    data,
    );

    V2:

    dataLayout.encode(
    {
    instruction: 23, // new code of withdraw instruction
    amount: new BN(amount),
    validator_index: validatorIndex,
    },
    data,
    );

    For validatorIndex see unstake page.

    • validator_list had been added to instructions keys:
      const keys = [
    { pubkey: solidoInstanceId, isSigner: false, isWritable: true },
    { pubkey: payerAddress, isSigner: true, isWritable: false },
    { pubkey: senderStSolAccountAddress, isSigner: false, isWritable: true },
    { pubkey: stSolMintAddress, isSigner: false, isWritable: true },
    { pubkey: new PublicKey(validator.pubkey.toArray('le')), isSigner: false, isWritable: false },
    { pubkey: validatorStakeAccount, isSigner: false, isWritable: true },
    { pubkey: stakeAccount, isSigner: true, isWritable: true },
    { pubkey: stakeAuthority, isSigner: false, isWritable: false },
    + { pubkey: new PublicKey(accountInfo.validators_list), isSigner: false, isWritable: true },
    { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
    ];

    Full change of account schema:
      const schema = new Map([
    [
    ExchangeRate,
    {
    kind: 'struct',
    fields: [
    ['computed_in_epoch', 'u64'],
    ['st_sol_supply', 'u64'],
    ['sol_balance', 'u64'],
    ],
    },
    ],
    [
    LamportsHistogram,
    {
    kind: 'struct',
    fields: [
    ['counts1', 'u64'],
    ['counts2', 'u64'],
    ['counts3', 'u64'],
    ['counts4', 'u64'],
    ['counts5', 'u64'],
    ['counts6', 'u64'],
    ['counts7', 'u64'],
    ['counts8', 'u64'],
    ['counts9', 'u64'],
    ['counts10', 'u64'],
    ['counts11', 'u64'],
    ['counts12', 'u64'],
    ['total', 'u64'],
    ],
    },
    ],
    [
    WithdrawMetric,
    {
    kind: 'struct',
    fields: [
    ['total_st_sol_amount', 'u64'],
    ['total_sol_amount', 'u64'],
    ['count', 'u64'],
    ],
    },
    ],
    [
    Metrics,
    {
    kind: 'struct',
    fields: [
    ['fee_treasury_sol_total', 'u64'],
    ['fee_validation_sol_total', 'u64'],
    ['fee_developer_sol_total', 'u64'],
    ['st_sol_appreciation_sol_total', 'u64'],
    ['fee_treasury_st_sol_total', 'u64'],
    ['fee_validation_st_sol_total', 'u64'],
    ['fee_developer_st_sol_total', 'u64'],
    ['deposit_amount', LamportsHistogram],
    ['withdraw_amount', WithdrawMetric],
    ],
    },
    ],
    - [
    - SeedRange,
    - {
    - kind: 'struct',
    - fields: [
    - ['begin', 'u64'],
    - ['end', 'u64'],
    - ],
    - },
    - ],
    - [
    - Validator,
    - {
    - kind: 'struct',
    - fields: [
    - ['fee_credit', 'u64'],
    - ['fee_address', 'u256'],
    - ['stake_seeds', SeedRange],
    - ['unstake_seeds', SeedRange],
    - ['stake_accounts_balance', 'u64'],
    - ['unstake_accounts_balance', 'u64'],
    - ['active', 'u8'],
    - ],
    - },
    - ],
    - [
    - PubKeyAndEntry,
    - {
    - kind: 'struct',
    - fields: [
    - ['pubkey', 'u256'],
    - ['entry', Validator],
    - ],
    - },
    - ],
    - [
    - PubKeyAndEntryMaintainer,
    - {
    - kind: 'struct',
    - fields: [
    - ['pubkey', 'u256'],
    - ['entry', [0]],
    - ],
    - },
    - ],
    [
    RewardDistribution,
    {
    kind: 'struct',
    fields: [
    ['treasury_fee', 'u32'],
    - ['validation_fee', 'u32'],
    ['developer_fee', 'u32'],
    ['st_sol_appreciation', 'u32'],
    ],
    },
    ],
    [
    FeeRecipients,
    {
    kind: 'struct',
    fields: [
    - ['treasury_account', 'u256'],
    + ['treasury_account', [32]],
    - ['developer_account', 'u256'],
    + ['developer_account', [32]],
    ],
    },
    ],
    - [
    - Validators,
    - {
    - kind: 'struct',
    - fields: [
    - ['entries', [PubKeyAndEntry]],
    - ['maximum_entries', 'u32'],
    - ],
    - },
    - ],
    - [
    - Maintainers,
    - {
    - kind: 'struct',
    - fields: [
    - ['entries', [PubKeyAndEntryMaintainer]],
    - ['maximum_entries', 'u32'],
    - ],
    - },
    - ],
    [
    Lido,
    {
    kind: 'struct',
    fields: [
    + ['account_type', 'u8'],

    ['lido_version', 'u8'],

    - ['manager', 'u256'],
    + ['manager', [32]],

    - ['st_sol_mint', 'u256'],
    + ['st_sol_mint', [32]],

    ['exchange_rate', ExchangeRate],

    ['sol_reserve_authority_bump_seed', 'u8'],
    ['stake_authority_bump_seed', 'u8'],
    ['mint_authority_bump_seed', 'u8'],
    ['rewards_withdraw_authority_bump_seed', 'u8'],

    ['reward_distribution', RewardDistribution],

    ['fee_recipients', FeeRecipients],

    ['metrics', Metrics],

    - ['validators', Validators],
    + ['validator_list', [32]],

    - ['maintainers', Maintainers],
    + ['maintainer_list', [32]],

    + ['max_commission_percentage', 'u8'],
    ],
    },
    ],
    ]);

    + const validatorsSchema = new Map([
    + [
    + ListHeader,
    + {
    + kind: 'struct',
    + fields: [
    + ['account_type', 'u8'],
    + ['lido_version', 'u8'],
    + ['max_entries', 'u32'],
    + ],
    + },
    + ],
    + [
    + SeedRange,
    + {
    + kind: 'struct',
    + fields: [
    + ['begin', 'u64'],
    + ['end', 'u64'],
    + ],
    + },
    + ],
    + [
    + ValidatorClass,
    + {
    + kind: 'struct',
    + fields: [
    + ['vote_account_address', [32]],
    + ['stake_seeds', SeedRange],
    + ['unstake_seeds', SeedRange],
    + ['stake_accounts_balance', 'u64'],
    + ['unstake_accounts_balance', 'u64'],
    + ['effective_stake_balance', 'u64'],
    + ['active', 'u8'],
    + ],
    + },
    + ],
    + [
    + AccountList,
    + {
    + kind: 'struct',
    + fields: [
    + ['header', ListHeader],
    + ['entries', [ValidatorClass]],
    + ],
    + },
    + ],
    + ]);
    - + \ No newline at end of file diff --git a/frontend-integration/manual-instructions/v1/stake/index.html b/frontend-integration/manual-instructions/v1/stake/index.html index 83864ef4..479b6616 100644 --- a/frontend-integration/manual-instructions/v1/stake/index.html +++ b/frontend-integration/manual-instructions/v1/stake/index.html @@ -12,7 +12,7 @@ Stake | Lido on Solana - + @@ -21,7 +21,7 @@ Or see new version if you are new.

    info

    We highly recommend use our SDK, so we could support you better in case of some problems. Also, integration with SDK is much easier & more simple than manually.

    Live integration on Mainnet - http://solana.lido.fi/

    In this document, we walk through the steps to integrate a web application with the Lido deposit function.

    This guide assumes the web application is written in JavaScript / Typescript and has ready access to the @solana/web3.js and @solana/spl-token library.

    note

    The code snippets present in this doc might not be up-to-date with the current codebase. Please verify once before using.

    Step 1 : Connecting to a Solana wallet

    Solana wallets that are known to work well with the Lido program are Phantom, Solflare, Ledger and Solong.

    • The wallet should expose the following spec
      • connect function that triggers a connection request to the wallet
      • publicKey to retrieve the public key of the connected account
      • signTransaction function to send the transaction
      • disconnect function to trigger a disconnection request
      • Optional - throws "connect" & "disconnect" events

    The next step assumes:

    • a wallet is loaded in the interface
    • and you have access to the variable LIDO_ADDRESS which is the address of the account that stores the state of the deployed Lido Program.

    Step 2 : Fetching Lido program state to retrieve relevant data

    Install and require @solana/web3.js library in your program

    yarn add @solana/web3.js

    Use getAccountInfo(LIDO_ADDRESS) function from this library to fetch the Lido program data (in the form of a buffer)

    const accountInfo = await connection.getAccountInfo(LIDO_ADDRESS);

    The data structure storing the Lido state(v1.0.0) has the form

    pub struct Lido {
    /// Version number for the Lido
    pub lido_version: u8,
    /// Manager of the Lido program, able to execute administrative functions
    #[serde(serialize_with = "serialize_b58")]
    pub manager: Pubkey,
    /// The SPL Token mint address for stSOL.
    #[serde(serialize_with = "serialize_b58")]
    pub st_sol_mint: Pubkey,
    /// Exchange rate to use when depositing.
    pub exchange_rate: ExchangeRate,
    /// Bump seeds for signing messages on behalf of the authority
    pub sol_reserve_account_bump_seed: u8,
    pub stake_authority_bump_seed: u8,
    pub mint_authority_bump_seed: u8,
    pub rewards_withdraw_authority_bump_seed: u8,
    /// How rewards are distributed.
    pub reward_distribution: RewardDistribution,
    /// Accounts of the fee recipients.
    pub fee_recipients: FeeRecipients,
    /// Metrics for informational purposes.
    ///
    /// Metrics are only written to, no program logic should depend on these values.
    /// An off-chain program can load a snapshot of the `Lido` struct, and expose
    /// these metrics.
    pub metrics: Metrics,
    /// Map of enrolled validators, maps their vote account to `Validator` details.
    pub validators: Validators,
    /// The set of maintainers.
    ///
    /// Maintainers are granted low security risk privileges. Maintainers are
    /// expected to run the maintenance daemon, that invokes the maintenance
    /// operations. These are gated on the signer being present in this set.
    /// In the future we plan to make maintenance operations callable by anybody.
    pub maintainers: Maintainers,
    }

    Create a borsh schema to deserialize the data.

    class Lido {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class SeedRange {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class Validator {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class PubKeyAndEntry {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class PubKeyAndEntryMaintainer {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class RewardDistribution {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class FeeRecipients {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class Validators {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class Maintainers {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class ExchangeRate {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class Metrics {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class LamportsHistogram {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    class WithdrawMetric {
    constructor(data) {
    Object.assign(this, data);
    }
    }
    const schema = new Map([
    [
    ExchangeRate,
    {
    kind: 'struct',
    fields: [
    ['computed_in_epoch', 'u64'],
    ['st_sol_supply', 'u64'],
    ['sol_balance', 'u64'],
    ],
    },
    ],
    [
    LamportsHistogram,
    {
    kind: 'struct',
    fields: [
    ['counts1', 'u64'],
    ['counts2', 'u64'],
    ['counts3', 'u64'],
    ['counts4', 'u64'],
    ['counts5', 'u64'],
    ['counts6', 'u64'],
    ['counts7', 'u64'],
    ['counts8', 'u64'],
    ['counts9', 'u64'],
    ['counts10', 'u64'],
    ['counts11', 'u64'],
    ['counts12', 'u64'],
    ['total', 'u64'],
    ],
    },
    ],
    [
    WithdrawMetric,
    {
    kind: 'struct',
    fields: [
    ['total_st_sol_amount', 'u64'],
    ['total_sol_amount', 'u64'],
    ['count', 'u64'],
    ],
    },
    ],
    [
    Metrics,
    {
    kind: 'struct',
    fields: [
    ['fee_treasury_sol_total', 'u64'],
    ['fee_validation_sol_total', 'u64'],
    ['fee_developer_sol_total', 'u64'],
    ['st_sol_appreciation_sol_total', 'u64'],
    ['fee_treasury_st_sol_total', 'u64'],
    ['fee_validation_st_sol_total', 'u64'],
    ['fee_developer_st_sol_total', 'u64'],
    ['deposit_amount', LamportsHistogram],
    ['withdraw_amount', WithdrawMetric],
    ],
    },
    ],
    [
    SeedRange,
    {
    kind: 'struct',
    fields: [
    ['begin', 'u64'],
    ['end', 'u64'],
    ],
    },
    ],
    [
    Validator,
    {
    kind: 'struct',
    fields: [
    ['fee_credit', 'u64'],
    ['fee_address', 'u256'],
    ['stake_seeds', SeedRange],
    ['unstake_seeds', SeedRange],
    ['stake_accounts_balance', 'u64'],
    ['unstake_accounts_balance', 'u64'],
    ['active', 'u8'],
    ],
    },
    ],
    [
    PubKeyAndEntry,
    {
    kind: 'struct',
    fields: [
    ['pubkey', 'u256'],
    ['entry', Validator],
    ],
    },
    ],
    [
    PubKeyAndEntryMaintainer,
    {
    kind: 'struct',
    fields: [
    ['pubkey', 'u256'],
    ['entry', [0]],
    ],
    },
    ],
    [
    RewardDistribution,
    {
    kind: 'struct',
    fields: [
    ['treasury_fee', 'u32'],
    ['validation_fee', 'u32'],
    ['developer_fee', 'u32'],
    ['st_sol_appreciation', 'u32'],
    ],
    },
    ],
    [
    FeeRecipients,
    {
    kind: 'struct',
    fields: [
    ['treasury_account', 'u256'],
    ['developer_account', 'u256'],
    ],
    },
    ],
    [
    Validators,
    {
    kind: 'struct',
    fields: [
    ['entries', [PubKeyAndEntry]],
    ['maximum_entries', 'u32'],
    ],
    },
    ],
    [
    Maintainers,
    {
    kind: 'struct',
    fields: [
    ['entries', [PubKeyAndEntryMaintainer]],
    ['maximum_entries', 'u32'],
    ],
    },
    ],
    [
    Lido,
    {
    kind: 'struct',
    fields: [
    ['lido_version', 'u8'],
    ['manager', 'u256'],
    ['st_sol_mint', 'u256'],
    ['exchange_rate', ExchangeRate],
    ['sol_reserve_authority_bump_seed', 'u8'],
    ['stake_authority_bump_seed', 'u8'],
    ['mint_authority_bump_seed', 'u8'],
    ['rewards_withdraw_authority_bump_seed', 'u8'],
    ['reward_distribution', RewardDistribution],
    ['fee_recipients', FeeRecipients],
    ['metrics', Metrics],
    ['validators', Validators],
    ['maintainers', Maintainers],
    ],
    },
    ],
    ]);

    Deserialize the data using the above schema

    import { deserializeUnchecked } from 'borsh';
    // We use deserializeUnchecked because Validators and Maintainers entries' length varies with time
    // It deserializes object from bytes using schema, without checking the length read
    const deserializedAccountInfo = deserializeUnchecked(
    schema,
    Lido,
    accountInfo.data,
    );

    Calculate the reserve authority and mint authority address by passing LIDO_ADDRESS buffer and reserve_account for reserve authority and mint_authority for mint authority buffer as seeds to findProgramAddress() along with the PROGRAM_ID

    import { PublicKey } from '@solana/web3.js';
    // Reserve authority
    const bufferArray = [
    LIDO_ADDRESS.toBuffer(),
    Buffer.from('reserve_account'),
    ];
    const [reserveAccount] = await PublicKey.findProgramAddress(bufferArray, PROGRAM_ID);
    // Mint authority
    const bufferArray = [
    LIDO_ADDRESS.toBuffer(),
    Buffer.from('mint_authority'),
    ];
    const [mintAuthority] = await PublicKey.findProgramAddress(bufferArray, PROGRAM_ID);

    Step 3 : Ensure an stSOL recipient account exists

    The Deposit instruction requires a recipient address - that will receive stSOL as liquid representation of the deposited SOL. Before we make a deposit from a user's wallet, we need to make sure such a recipient account exists - for the depositor to receive stSOL.

    Fetch all accounts for the stSOL mint of the staker

    • If at least one such account exists, select the first one and proceed to the next step
    • If no such account exists, continue with this section.

    If no account exists

    • Fetch the associated token account for the payer account
    • Add the instruction to create the new associated token account
    • Return the associated token account's public key
    import { AccountLayout, Token, ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token';
    const { value: accounts } = await connection.getTokenAccountsByOwner(payer, {
    mint: stSolMint,
    });
    const recipient = accounts[0];
    if (recipient) {
    return recipient.pubkey;
    }
    // Creating the associated token account if not already exist
    const associatedStSolAccount = await Token.getAssociatedTokenAddress(
    ASSOCIATED_TOKEN_PROGRAM_ID,
    TOKEN_PROGRAM_ID,
    stSolMint,
    payer,
    );
    transaction.add(
    Token.createAssociatedTokenAccountInstruction(
    ASSOCIATED_TOKEN_PROGRAM_ID,
    TOKEN_PROGRAM_ID,
    stSolMint,
    associatedStSolAccount,
    payer,
    payer,
    ),
    );
    return associatedStSolAccount;

    Step 4 : Create Deposit Instruction

    • Create the buffer layout in the format of { instruction_code: 1 byte, amount: 8 bytes}
    • Encode the deposit data using the buffer layout
      import * as BufferLayout from 'buffer-layout';
      import BN from 'bn.js';
      const dataLayout = BufferLayout.struct([
      BufferLayout.u8('instruction'),
      BufferLayout.nu64('amount'), // little endian
      ]);
      const data = Buffer.alloc(dataLayout.span);
      dataLayout.encode(
      {
      instruction: 1, // 1 for deposit instruction
      amount: new BN(amount),
      },
      data,
      );
    • Set all keys for the deposit instruction using the program data we fetch earlier
      const keys = [
      {
      pubkey: lidoAddress,
      isSigner: false,
      isWritable: true,
      },
      { pubkey: payer, isSigner: true, isWritable: true },
      {
      pubkey: recipient,
      isSigner: false,
      isWritable: true,
      },
      {
      pubkey: stSolMint,
      isSigner: false,
      isWritable: true,
      },
      { pubkey: reserveAccount, isSigner: false, isWritable: true },
      { pubkey: mintAuthority, isSigner: false, isWritable: false },
      { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
      { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
      ];
    • Add the instruction to the transaction
      transaction.add(
      new TransactionInstruction({
      keys,
      programId: PROGRAM_ID,
      data,
      }),
      );

    Step 5 : Sign and send Transaction

    • Create a new transaction with the fee payer as the staker
    • Add all the above instructions in the sequence
    • If we have created a new stSOL, partially sign the transaction using the newAccount's keypair
    • Sign the transaction
    • Send the transaction
    // Create new transaction
    const transaction = new Transaction({ feePayer: payer });
    // Set recent blockhash
    const { blockhash } = await connection.getRecentBlockhash();
    transaction.recentBlockhash = blockhash;
    // Add all the above instructions
    const recipient = await ensureTokenAccount(
    connection,
    transaction,
    payer,
    stSolMint
    );
    await depositInstruction(payer, amount, recipient, transaction, config);
    // Sign the transaction using the wallet
    const signed = wallet.signTransaction(transaction);
    // Send the serialized signed transaction to the network
    connection.sendRawTransaction(
    signed.serialize(),
    );

    Useful Nuggets

    • How to get the total number of stSOL holders?
      // Filter out stSOL token addresses
      const memcmpFilter = { memcmp: { bytes: ST_SOL_MINT.toString(), offset: 0 } };
      const config = {
      filters: [{ dataSize: 165 }, memcmpFilter],
      encoding: 'jsonParsed',
      };
      // Get program accounts using the above filters
      const accounts = await connection.getParsedProgramAccounts(
      TOKEN_PROGRAM_ID,
      config,
      );
      const totalStSolHolders = accounts.length;
    • How to get the stSOL/SOL exchange rate for the current epoch?
        const accountInfo = await getAccountInfo(connection, lidoAddress);
      // Fetch SOL and stSOL balance
      const totalSolInLamports = accountInfo.exchange_rate.sol_balance.toNumber();
      const stSolSupplyInLamports =
      accountInfo.exchange_rate.st_sol_supply.toNumber();
      // Calculate the stSOL/SOL exchange rate
      const exchangeRate = totalStSolSupplyInLamports/totalSolInLamports;
    • How to get the current amount of SOL staked with Lido?
        const accountInfo = await getAccountInfo(connection, lidoAddress);
      // Find reserve account pubkey
      const bufferArray = [
      lidoAddress.toBuffer(),
      Buffer.from('reserve_account'),
      ];
      const [reserveAccount] = await PublicKey.findProgramAddress(bufferArray, programId);
      // Fetch balance and rent for reserve account
      const reserveAccountInfo = await connection.getAccountInfo(reserveAccount);
      const reserveAccountRent = await connection.getMinimumBalanceForRentExemption(
      reserveAccountInfo.data.byteLength,
      );
      const reserveAccountBalanceInLamports =
      reserveAccountInfo.lamports - reserveAccountRent;
      const validatorsStakeAccountsBalanceInLamports = accountInfo.validators.entries
      .map((pubKeyAndEntry) => pubKeyAndEntry.entry)
      .map((validator) => validator.stake_accounts_balance.toNumber())
      .reduce((acc, current) => acc + current, 0);
      const totalStakedInLamports = reserveAccountBalanceInLamports + validatorsStakeAccountsBalanceInLamports;
    - + \ No newline at end of file diff --git a/frontend-integration/manual-instructions/v1/unstake/index.html b/frontend-integration/manual-instructions/v1/unstake/index.html index 6180007b..0033e88c 100644 --- a/frontend-integration/manual-instructions/v1/unstake/index.html +++ b/frontend-integration/manual-instructions/v1/unstake/index.html @@ -12,7 +12,7 @@ UnStake | Lido on Solana - + @@ -20,7 +20,7 @@

    UnStake

    danger

    We have already migrated to second version of procotol (solido), so these instructions aren't working anymore, please see migration guide for migrating to version 2. Or see new version if you are new.

    info

    We highly recommend use our SDK, so we could support you better in case of some problems. Also, integration with SDK is much easier & more simple than manually.

    Step 1: Fetching Lido program state to retrieve relevant data

    const accountInfo = await connection.getAccountInfo(LIDO_ADDRESS);

    Use getAccountInfo(LIDO_ADDRESS) function from this library to fetch the Lido program data (in the form of a buffer).

    • Create a borsh schema to deserialize the data:
    class Lido {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class SeedRange {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class Validator {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class PubKeyAndEntry {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class PubKeyAndEntryMaintainer {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class RewardDistribution {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class FeeRecipients {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class Validators {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class Maintainers {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class ExchangeRate {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class Metrics {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class LamportsHistogram {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class WithdrawMetric {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    const schema = new Map([
    [
    ExchangeRate,
    {
    kind: 'struct',
    fields: [
    ['computed_in_epoch', 'u64'],
    ['st_sol_supply', 'u64'],
    ['sol_balance', 'u64'],
    ],
    },
    ],
    [
    LamportsHistogram,
    {
    kind: 'struct',
    fields: [
    ['counts1', 'u64'],
    ['counts2', 'u64'],
    ['counts3', 'u64'],
    ['counts4', 'u64'],
    ['counts5', 'u64'],
    ['counts6', 'u64'],
    ['counts7', 'u64'],
    ['counts8', 'u64'],
    ['counts9', 'u64'],
    ['counts10', 'u64'],
    ['counts11', 'u64'],
    ['counts12', 'u64'],
    ['total', 'u64'],
    ],
    },
    ],
    [
    WithdrawMetric,
    {
    kind: 'struct',
    fields: [
    ['total_st_sol_amount', 'u64'],
    ['total_sol_amount', 'u64'],
    ['count', 'u64'],
    ],
    },
    ],
    [
    Metrics,
    {
    kind: 'struct',
    fields: [
    ['fee_treasury_sol_total', 'u64'],
    ['fee_validation_sol_total', 'u64'],
    ['fee_developer_sol_total', 'u64'],
    ['st_sol_appreciation_sol_total', 'u64'],
    ['fee_treasury_st_sol_total', 'u64'],
    ['fee_validation_st_sol_total', 'u64'],
    ['fee_developer_st_sol_total', 'u64'],
    ['deposit_amount', LamportsHistogram],
    ['withdraw_amount', WithdrawMetric],
    ],
    },
    ],
    [
    SeedRange,
    {
    kind: 'struct',
    fields: [
    ['begin', 'u64'],
    ['end', 'u64'],
    ],
    },
    ],
    [
    Validator,
    {
    kind: 'struct',
    fields: [
    ['fee_credit', 'u64'],
    ['fee_address', 'u256'],
    ['stake_seeds', SeedRange],
    ['unstake_seeds', SeedRange],
    ['stake_accounts_balance', 'u64'],
    ['unstake_accounts_balance', 'u64'],
    ['active', 'u8'],
    ],
    },
    ],
    [
    PubKeyAndEntry,
    {
    kind: 'struct',
    fields: [
    ['pubkey', 'u256'],
    ['entry', Validator],
    ],
    },
    ],
    [
    PubKeyAndEntryMaintainer,
    {
    kind: 'struct',
    fields: [
    ['pubkey', 'u256'],
    ['entry', [0]],
    ],
    },
    ],
    [
    RewardDistribution,
    {
    kind: 'struct',
    fields: [
    ['treasury_fee', 'u32'],
    ['validation_fee', 'u32'],
    ['developer_fee', 'u32'],
    ['st_sol_appreciation', 'u32'],
    ],
    },
    ],
    [
    FeeRecipients,
    {
    kind: 'struct',
    fields: [
    ['treasury_account', 'u256'],
    ['developer_account', 'u256'],
    ],
    },
    ],
    [
    Validators,
    {
    kind: 'struct',
    fields: [
    ['entries', [PubKeyAndEntry]],
    ['maximum_entries', 'u32'],
    ],
    },
    ],
    [
    Maintainers,
    {
    kind: 'struct',
    fields: [
    ['entries', [PubKeyAndEntryMaintainer]],
    ['maximum_entries', 'u32'],
    ],
    },
    ],
    [
    Lido,
    {
    kind: 'struct',
    fields: [
    ['lido_version', 'u8'],

    ['manager', 'u256'],

    ['st_sol_mint', 'u256'],

    ['exchange_rate', ExchangeRate],

    ['sol_reserve_authority_bump_seed', 'u8'],
    ['stake_authority_bump_seed', 'u8'],
    ['mint_authority_bump_seed', 'u8'],
    ['rewards_withdraw_authority_bump_seed', 'u8'],

    ['reward_distribution', RewardDistribution],

    ['fee_recipients', FeeRecipients],

    ['metrics', Metrics],

    ['validators', Validators],

    ['maintainers', Maintainers],
    ],
    },
    ],
    ]);
    • Deserialize the data using above schema:
    import { deserializeUnchecked } from 'borsh';
    // We use deserializeUnchecked because Validators and Maintainers entries' length varies with time
    // It deserializes object from bytes using schema, without checking the length read
    const deserializedAccountInfo = deserializeUnchecked(
    schema,
    Lido,
    accountInfo.data,
    );

    Step 2: Sign new Transaction

    const newStakeAccount = Keypair.generate();
    // Create new transaction
    const transaction = new Transaction({ feePayer: payer });
    // Set recent blockhash
    const { blockhash } = await connection.getLatestBlockhash();
    transaction.recentBlockhash = blockhash;

    Step 3: Create Withdraw Instruction

    • Create the buffer layout in the format of { instruction_code: 1 byte, amount: 8 bytes}
    • Encode the deposit data using the buffer layout:
    import * as BufferLayout from 'buffer-layout';
    import BN from 'bn.js';

    const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction'), BufferLayout.nu64('amount')]);

    const data = Buffer.alloc(dataLayout.span);
    dataLayout.encode(
    {
    instruction: 2, // withdraw instruction
    amount: new BN(amount),
    },
    data,
    );
    • Set all keys for the deposit instruction using the program data we fetch earlier:
    import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
    import {
    Keypair,
    PublicKey,
    StakeProgram,
    SystemProgram,
    SYSVAR_CLOCK_PUBKEY,
    } from '@solana/web3.js';

    const calculateStakeAuthority = async (lidoAddress, programId) => {
    const bufferArray = [lidoAddress.toBuffer(), Buffer.from('stake_authority')];

    const mint = await PublicKey.findProgramAddress(bufferArray, programId);

    return mint[0];
    };

    const calculateStakeAccountAddress = async (lidoAddress, programId, validatorVoteAccount, seed) => {
    const bufferArray = [
    lidoAddress.toBuffer(),
    validatorVoteAccount.toBuffer(),
    Buffer.from('validator_stake_account'),
    seed.toArray('le', 8),
    ];

    const [stakeAccountAddress] = await PublicKey.findProgramAddress(bufferArray, programId);

    return stakeAccountAddress;
    };

    const getHeaviestValidator = async (validatorEntries) => {
    const sortedValidatorEntries = validatorEntries.sort(
    ({ entry: validatorA }, { entry: validatorB }) =>
    validatorB.stake_accounts_balance.toNumber() - validatorA.stake_accounts_balance.toNumber(),
    );

    const heaviestValidator = sortedValidatorEntries[0];

    return heaviestValidator;
    };

    const stakeAuthority = await calculateStakeAuthority(lidoAddress, programId);
    const validator = await getHeaviestValidator(accountInfo.validators.entries);

    const validatorStakeAccount = await calculateStakeAccountAddress(
    lidoAddress,
    programId,
    new PublicKey(validator.pubkey.toArray('le')),
    validator.entry.stake_seeds.begin,
    );

    const keys = [
    {
    pubkey: lidoAddress,
    isSigner: false,
    isWritable: true,
    },
    { pubkey: payer, isSigner: true, isWritable: false },
    {
    pubkey: stSolAddress,
    isSigner: false,
    isWritable: true,
    },
    {
    pubkey: stSolMint,
    isSigner: false,
    isWritable: true,
    },
    {
    pubkey: new PublicKey(validator.pubkey.toArray('le')),
    isSigner: false,
    isWritable: false,
    },
    { pubkey: validatorStakeAccount, isSigner: false, isWritable: true },
    {
    pubkey: newStakeAccount.publicKey, // step 2 variable
    isSigner: true,
    isWritable: true,
    },
    { pubkey: stakeAuthority, isSigner: false, isWritable: false },
    { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
    ];
    • Add the instruction to the transaction:
    transaction.add(
    new TransactionInstruction({
    keys,
    programId: PROGRAM_ID,
    data,
    }),
    );

    Step 4: Create deactivate transaction & add its instructions to transaction

    import { StakeProgram } from '@solana/web3.js';

    const deactivateTransaction = StakeProgram.deactivate({
    authorizedPubkey: payer,
    stakePubkey: newStakeAccount.publicKey,
    });

    transaction.add(...deactivateTransaction.instructions);

    transaction.partialSign(newStakeAccount); // step 2 variables
    - + \ No newline at end of file diff --git a/frontend-integration/manual-instructions/v2/stake/index.html b/frontend-integration/manual-instructions/v2/stake/index.html index d1f6034d..00b491d4 100644 --- a/frontend-integration/manual-instructions/v2/stake/index.html +++ b/frontend-integration/manual-instructions/v2/stake/index.html @@ -12,7 +12,7 @@ Stake | Lido on Solana - + @@ -20,7 +20,7 @@

    Stake

    info

    We highly recommend use our SDK, so we could support you better in case of some problems. Also, integration with SDK is much easier & more simple than manually.

    Live integration on Mainnet - http://solana.lido.fi/

    In this document, we walk through the steps to integrate a web application with the Lido deposit function.

    Step 1: Ensure an stSOL recipient account exists

    The Deposit instruction requires a recipient address - that will receive stSOL as liquid representation of the deposited SOL. Before we make a deposit from a user's wallet, we need to make sure such a recipient account exists - for the depositor to receive stSOL.

    Fetch all accounts for the stSOL mint of the staker

    • If at least one such account exists, select the first one and proceed to the next step
    • If no such account exists, continue with this section.

    If no account exists

    • Fetch the associated token account for the payer account
    • Add the instruction to create the new associated token account
    • Return the associated token account's public key
    import { AccountLayout, Token, ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token';

    const { value: accounts } = await connection.getTokenAccountsByOwner(payer, {
    mint: stSolMint,
    });
    const recipient = accounts[0];

    if (recipient) {
    recipientStSolAddress = recipient.pubkey;
    }
    // Creating the associated token account if not already exist
    const associatedStSolAccount = await Token.getAssociatedTokenAddress(
    ASSOCIATED_TOKEN_PROGRAM_ID,
    TOKEN_PROGRAM_ID,
    stSolMint,
    payer,
    );

    transaction.add(
    Token.createAssociatedTokenAccountInstruction(
    ASSOCIATED_TOKEN_PROGRAM_ID,
    TOKEN_PROGRAM_ID,
    stSolMint,
    associatedStSolAccount,
    payer,
    payer,
    ),
    );

    const recipientStSolAddress = associatedStSolAccount;

    Step 2: Create Deposit Instruction

    • Create the buffer layout in the format of { instruction_code: 1 byte, amount: 8 bytes}:
    import { nu64, struct, u8 } from 'buffer-layout';

    const dataLayout = struct([u8('instruction'), nu64('amount')]);

    const data = Buffer.alloc(dataLayout.span);
    • Encode the deposit data using the buffer layout:
    import BN from 'bn.js';

    dataLayout.encode(
    {
    instruction: 1, // code of deposit instruction
    amount: new BN(amount),
    },
    data,
    );
    • Set all keys for the deposit instruction using the program data we fetch earlier:
    import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
    import {
    Keypair,
    PublicKey,
    StakeProgram,
    SystemProgram,
    SYSVAR_CLOCK_PUBKEY,
    } from '@solana/web3.js';

    const bufferArray = [
    LIDO_ADDRESS.toBuffer(),
    Buffer.from('reserve_account'),
    ];

    const [reserveAccount] = await PublicKey.findProgramAddress(bufferArray, programId);

    const bufferArrayMint = [
    LIDO_ADDRESS.toBuffer(),
    Buffer.from('mint_authority'),
    ];

    const [mintAuthority] = await PublicKey.findProgramAddress(bufferArrayMint, programId);

    const keys = [
    { pubkey: LIDO_ADDRESS, isSigner: false, isWritable: true },
    { pubkey: payerAddress, isSigner: true, isWritable: true }, // wallet.publicKey
    { pubkey: recipientStSolAddress, isSigner: false, isWritable: true },
    { pubkey: ST_SOL_MINT, isSigner: false, isWritable: true },
    { pubkey: reserveAccount, isSigner: false, isWritable: true },
    { pubkey: mintAuthority, isSigner: false, isWritable: false },
    { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    ];
    • Add the instruction to the transaction:
    transaction.add(
    new TransactionInstruction({
    keys,
    programId: PROGRAM_ID,
    data,
    }),
    );

    Step 3: Sign and send Transaction

    • Create a new transaction with the fee payer as the staker
    • Add all the above instructions in the sequence
    • If we have created a new stSOL, partially sign the transaction using the newAccount's keypair
    • Sign the transaction
    • Send the transaction
    // Create new transaction
    const transaction = new Transaction({ feePayer: payer });
    // Set recent blockhash
    const { blockhash } = await connection.getRecentBlockhash();
    transaction.recentBlockhash = blockhash;
    // Add all the above instructions
    const recipient = await ensureTokenAccount(
    connection,
    transaction,
    payer,
    stSolMint
    );
    await depositInstruction(payer, amount, recipient, transaction, config);
    // Sign the transaction using the wallet
    const signed = wallet.signTransaction(transaction);
    // Send the serialized signed transaction to the network
    connection.sendRawTransaction(
    signed.serialize(),
    );
    - + \ No newline at end of file diff --git a/frontend-integration/manual-instructions/v2/unstake/index.html b/frontend-integration/manual-instructions/v2/unstake/index.html index 260ec6a6..72fc2412 100644 --- a/frontend-integration/manual-instructions/v2/unstake/index.html +++ b/frontend-integration/manual-instructions/v2/unstake/index.html @@ -12,14 +12,14 @@ UnStake | Lido on Solana - +

    UnStake

    info

    We highly recommend use our SDK, so we could support you better in case of some problems. Also, integration with SDK is much easier & more simple than manually.

    Step 1: Fetching Lido program state to retrieve relevant data

    const accountInfo = await connection.getAccountInfo(LIDO_ADDRESS);

    Use getAccountInfo(LIDO_ADDRESS) function from this library to fetch the Lido program data (in the form of a buffer).

    • Create a borsh schema to deserialize the solido state data:
    class Lido {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class RewardDistribution {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class FeeRecipients {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class ExchangeRate {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class Metrics {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class LamportsHistogram {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class WithdrawMetric {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    const accountInfoScheme = new Map([
    [
    ExchangeRate,
    {
    kind: 'struct',
    fields: [
    ['computed_in_epoch', 'u64'],
    ['st_sol_supply', 'u64'],
    ['sol_balance', 'u64'],
    ],
    },
    ],
    [
    LamportsHistogram,
    {
    kind: 'struct',
    fields: [
    ['counts1', 'u64'],
    ['counts2', 'u64'],
    ['counts3', 'u64'],
    ['counts4', 'u64'],
    ['counts5', 'u64'],
    ['counts6', 'u64'],
    ['counts7', 'u64'],
    ['counts8', 'u64'],
    ['counts9', 'u64'],
    ['counts10', 'u64'],
    ['counts11', 'u64'],
    ['counts12', 'u64'],
    ['total', 'u64'],
    ],
    },
    ],
    [
    WithdrawMetric,
    {
    kind: 'struct',
    fields: [
    ['total_st_sol_amount', 'u64'],
    ['total_sol_amount', 'u64'],
    ['count', 'u64'],
    ],
    },
    ],
    [
    Metrics,
    {
    kind: 'struct',
    fields: [
    ['fee_treasury_sol_total', 'u64'],
    ['fee_validation_sol_total', 'u64'],
    ['fee_developer_sol_total', 'u64'],
    ['st_sol_appreciation_sol_total', 'u64'],
    ['fee_treasury_st_sol_total', 'u64'],
    ['fee_validation_st_sol_total', 'u64'],
    ['fee_developer_st_sol_total', 'u64'],
    ['deposit_amount', LamportsHistogram],
    ['withdraw_amount', WithdrawMetric],
    ],
    },
    ],
    [
    RewardDistribution,
    {
    kind: 'struct',
    fields: [
    ['treasury_fee', 'u32'],
    ['developer_fee', 'u32'],
    ['st_sol_appreciation', 'u32'],
    ],
    },
    ],
    [
    FeeRecipients,
    {
    kind: 'struct',
    fields: [
    ['treasury_account', [32]],
    ['developer_account', [32]],
    ],
    },
    ],
    [
    Lido,
    {
    kind: 'struct',
    fields: [
    ['account_type', 'u8'],

    ['lido_version', 'u8'],

    ['manager', [32]],

    ['st_sol_mint', [32]],

    ['exchange_rate', ExchangeRate],

    ['sol_reserve_authority_bump_seed', 'u8'],
    ['stake_authority_bump_seed', 'u8'],
    ['mint_authority_bump_seed', 'u8'],

    ['reward_distribution', RewardDistribution],

    ['fee_recipients', FeeRecipients],

    ['metrics', Metrics],

    ['validator_list', [32]],

    ['maintainer_list', [32]],

    ['max_commission_percentage', 'u8'],
    ],
    },
    ],
    ]);
    • Deserialize the data using above schema:
    import { deserializeUnchecked } from 'borsh';
    // It deserializes object from bytes using schema, without checking the length read
    const deserializedAccountInfo = deserializeUnchecked(
    accountInfoschema,
    Lido,
    accountInfo.data,
    );

    Step 2: Fetching Validators list account

    const validatorsList = new PublicKey(deserializedAccountInfo.validators_list);
    const validators = await connection.getAccountInfo(validatorsList);
    • Create a borsh schema to deserialize the validators data:
    class ListHeader {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class SeedRange {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class ValidatorClass {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    class AccountList {
    constructor(data) {
    Object.assign(this, data);
    }
    }

    const validatorsSchema = new Map([
    [
    ListHeader,
    {
    kind: 'struct',
    fields: [
    ['account_type', 'u8'],
    ['lido_version', 'u8'],
    ['max_entries', 'u32'],
    ],
    },
    ],
    [
    SeedRange,
    {
    kind: 'struct',
    fields: [
    ['begin', 'u64'],
    ['end', 'u64'],
    ],
    },
    ],
    [
    ValidatorClass,
    {
    kind: 'struct',
    fields: [
    ['vote_account_address', [32]],
    ['stake_seeds', SeedRange],
    ['unstake_seeds', SeedRange],
    ['stake_accounts_balance', 'u64'],
    ['unstake_accounts_balance', 'u64'],
    ['effective_stake_balance', 'u64'],
    ['active', 'u8'],
    ],
    },
    ],
    [
    AccountList,
    {
    kind: 'struct',
    fields: [
    ['header', ListHeader],
    ['entries', [ValidatorClass]],
    ],
    },
    ],
    ]);
    • Deserialize the data using above schema:
    const deserializedValidators = deserializeUnchecked(
    validatorsSchema,
    AccountList,
    validators.data,
    );

    Step 3: Sign new Transaction

    const newStakeAccount = Keypair.generate();
    // Create new transaction
    const transaction = new Transaction({ feePayer: payer });
    // Set recent blockhash
    const { blockhash } = await connection.getLatestBlockhash();
    transaction.recentBlockhash = blockhash;

    Step 4: Create Withdraw Instruction

    • Create the buffer layout in the format of { instruction_code: 1 byte, amount: 8 bytes, validator_index: 4 bytes}:
    import { nu64, struct, u32, u8 } from 'buffer-layout';

    const dataLayout = struct([u8('instruction'), nu64('amount'), u32('validator_index')]);

    const data = Buffer.alloc(dataLayout.span);
    • Get heaviest validator index:
    const getHeaviestValidator = (validatorEntries) => {
    const sortedValidators = validatorEntries.sort(
    (validatorA, validatorB) =>
    validatorB.stake_accounts_balance.toNumber() - validatorA.stake_accounts_balance.toNumber(),
    );

    return sortedValidators[0];
    };

    const getValidatorIndex = (validatorEntries, validator) =>
    validatorEntries.findIndex(
    ({ vote_account_address: voteAccountAddress }) =>
    voteAccountAddress.toString() === validator.vote_account_address.toString(),
    );

    const validator = getHeaviestValidator(validators);

    const validatorIndex = getValidatorIndex(validators, validator);
    • Encode the deposit data using the buffer layout:
    import BN from 'bn.js';

    dataLayout.encode(
    {
    instruction: 23, // code of withdraw instruction
    amount: new BN(amount),
    validator_index: validatorIndex,
    },
    data,
    );
    • Set all keys for the deposit instruction using the program data we fetch earlier:
    import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
    import {
    Keypair,
    PublicKey,
    StakeProgram,
    SystemProgram,
    SYSVAR_CLOCK_PUBKEY,
    } from '@solana/web3.js';

    const calculateStakeAuthority = async (lidoAddress, programId) => {
    const bufferArray = [lidoAddress.toBuffer(), Buffer.from('stake_authority')];

    const mint = await PublicKey.findProgramAddress(bufferArray, programId);

    return mint[0];
    };

    const calculateStakeAccountAddress = async (lidoAddress, programId, validatorVoteAccount, seed) => {
    const bufferArray = [
    lidoAddress.toBuffer(),
    validatorVoteAccount.toBuffer(),
    Buffer.from('validator_stake_account'),
    seed.toArray('le', 8),
    ];

    const [stakeAccountAddress] = await PublicKey.findProgramAddress(bufferArray, programId);

    return stakeAccountAddress;
    };

    const getStSolAccountsForUser = async (owner) => {
    const stSolAccounts = [];

    const { value } = await connection.getParsedTokenAccountsByOwner(owner, {
    mint: ST_SOL_MINT,
    });

    value.forEach((v) => {
    const address = v.pubkey;
    const balanceInLamports = parseInt(v.account.data.parsed?.info?.tokenAmount?.amount ?? '0', 10);

    stSolAccounts.push({ address, balanceInLamports });
    });

    return stSolAccounts;
    };

    const stakeAuthority = await calculateStakeAuthority(lidoAddress, programId);
    const validator = await getHeaviestValidator(validators);

    const senderStSolAccountAddress = await getStSolAccountsForUser(wallet.publicKey); // payerAddress

    const validatorStakeAccount = await calculateStakeAccountAddress(
    LIDO_ADDRESS,
    PROGRAM_ID,
    new PublicKey(validator.vote_account_address),
    validator.stake_seeds.begin,
    );

    const keys = [
    { pubkey: solidoInstanceId, isSigner: false, isWritable: true },
    { pubkey: payerAddress, isSigner: true, isWritable: false },
    { pubkey: senderStSolAccountAddress, isSigner: false, isWritable: true },
    { pubkey: ST_SOL_MINT, isSigner: false, isWritable: true },
    { pubkey: new PublicKey(validator.vote_account_address), isSigner: false, isWritable: false },
    { pubkey: validatorStakeAccount, isSigner: false, isWritable: true },
    { pubkey: stakeAccount, isSigner: true, isWritable: true },
    { pubkey: stakeAuthority, isSigner: false, isWritable: false },
    { pubkey: validatorsList, isSigner: false, isWritable: true }, // step 2
    { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
    ];
    • Add the instruction to the transaction:
    transaction.add(
    new TransactionInstruction({
    keys,
    programId: PROGRAM_ID,
    data,
    }),
    );

    Step 5: Create deactivate transaction & add its instructions to transaction

    import { StakeProgram } from '@solana/web3.js';

    const deactivateTransaction = StakeProgram.deactivate({
    authorizedPubkey: payer,
    stakePubkey: newStakeAccount.publicKey,
    });

    transaction.add(...deactivateTransaction.instructions);

    transaction.partialSign(newStakeAccount); // step 2 variables
    - + \ No newline at end of file diff --git a/frontend-integration/sdk/banner/index.html b/frontend-integration/sdk/banner/index.html index 5de20f50..24d00c15 100644 --- a/frontend-integration/sdk/banner/index.html +++ b/frontend-integration/sdk/banner/index.html @@ -12,7 +12,7 @@ Banner | Lido on Solana - + @@ -22,7 +22,7 @@

    9.35 APY + DeFi Yields

    Stake SOL with Lido and receive stSOL while staking.
    Put stSOL in to DeFI integrations and earn up to 272.14% APY


    Vertical mode

    Props:

    • referrerId - Solana Referral Address. Read more.
    • width - This option is for customising width of vertical mode. Default and best fit value is 335px.
    • direction = horizontal
    <LidoStakeBanner referrerId="your_solana_referral_address" direction="vertical" />

    9.35 APY + DeFi Yields

    Stake SOL with Lido and receive stSOL while staking.
    Put stSOL in to DeFI integrations and earn up to 272.14% APY


    info

    Banner is responsive, in devices with less than 767px width the banner automatically rotates from horizontal to vertical.

    width props for horizontal mode always 100%, use wrapper, if need limited.

    - + \ No newline at end of file diff --git a/frontend-integration/sdk/errors/index.html b/frontend-integration/sdk/errors/index.html index 80f868d7..5c7ed21d 100644 --- a/frontend-integration/sdk/errors/index.html +++ b/frontend-integration/sdk/errors/index.html @@ -12,14 +12,14 @@ Error codes | Lido on Solana - +

    Error codes


    All known errors we wrap adding some extra fields to make it easier controlling exceptions. Also, it's possible to use message field of Error object to inform users about the details of exception.

    Additional fields to Error object:

    • code: number - error code
    • codeDesc: string - error code definition

    This table lists the error code information returned by the SolidoSDK when it is called.

    Error codeError code definitionMessage
    100CANNOT_CONFIRM_TRANSACTIONGot error from Solana blockchain during transaction confirmation, so this error could have different messages (signature is not base58 encoded/transaction was not confirmed in N seconds/signature has invalid length etc.)
    200NO_VALIDATORSCouldn't fetch validators list
    300UNSUPPORTED_CLUSTERSolidoSDK doesn't support devnet, specify mainnet-beta or testnet
    301UNSTAKE_UNAVAILABLESorry, unStake is not available right now. Please contact lido developers for details.
    302NO_PUBLIC_KEYSolidoSDK: publicKey is null in wallet
    303NO_ACCOUNT_INFOCouldn't fetch getAccountInfo
    304NO_APY_DATACouldn't fetch apy data
    400EXCEED_MAXAmount must not exceed MAX(..)
    401PUBLIC_KEY_IS_PDAYour publicKey is PDA type. Please use allowOwnerOffCurve=true flag.
    402EXCEED_MINAmount must be greater than rent-exempt fee(..)

    Example

    try {
    const { transactionHash, stSolAccountAddress } = await solidoSDK.stake({
    amount: 20, // The amount of SOL-s which need to stake
    wallet: wallet, // Wallet instance with 1 Sol left
    });
    } catch (error) {
    console.error(error.code); // -> 400
    console.error(error.codeDesc); // -> 'EXCEED_MAX'
    console.error(error.message); // -> 'Amount must not exceed MAX(0.9988)'
    }
    - + \ No newline at end of file diff --git a/frontend-integration/sdk/index.html b/frontend-integration/sdk/index.html index 01b430e7..6fac4cb7 100644 --- a/frontend-integration/sdk/index.html +++ b/frontend-integration/sdk/index.html @@ -12,13 +12,13 @@ Introduction | Lido on Solana - +

    Introduction

    This SDK helps you integrate with Lido in three ways:

    1. Using React banner (simplest).
    2. Supporting a UI widget in your project (We provide js functions for staking, unstaking, statistics and transaction info).
    3. Use the staking widget with UI (coming soon).

    Using banner

    npm install @lidofinance/solido-sdk-banner
    import LidoStakeBanner from '@lidofinance/solido-sdk-banner';

    <LidoStakeBanner referrerId="your_solana_referral_address" direction="horizontal" />

    See Banner Section

    Using SDK

    npm install @lidofinance/solido-sdk
    import { SolidoSDK } from '@lidofinance/solido-sdk';

    try {
    const solidoSDK = new SolidoSDK('mainnet-beta', connection, 'your_solana_referral_address');

    await solidoSDK.stake({
    amount: 20, // The amount of SOL-s which need to stake
    wallet: wallet, // Wallet instance
    // Optional callback for getting information about transaction stage
    setTxStage: setTxStageCallback,
    });
    } catch (e) {
    // Handle Errors
    }

    See SDK Staking for details

    Using staking widget

    In progress, will be available soon.

    Learn more

    - + \ No newline at end of file diff --git a/frontend-integration/sdk/react-native/index.html b/frontend-integration/sdk/react-native/index.html index c644c82f..3a55bfe4 100644 --- a/frontend-integration/sdk/react-native/index.html +++ b/frontend-integration/sdk/react-native/index.html @@ -12,7 +12,7 @@ React Native | Lido on Solana - + @@ -26,7 +26,7 @@ It should be enough to install buffer and import it:

    import {Buffer} from 'buffer';
    global.Buffer = global.Buffer || Buffer;

    Example

    An example React Native app that demonstrates how to use the solido-sdk on react-native with interaction of a mobile wallet:

    Feel free to ask any questions if you get stuck: Discord: solana-dev-support.

    note
    • The example is working only on Android, because Solana Mobile Wallet Adapter doesn't support IOS yet.
    • Please use @lidofinance/solido-sdk@0.8.0 or above, because we made some specific optimizations & refactoring that will be useful also for react-native applications.
    - + \ No newline at end of file diff --git a/frontend-integration/sdk/sdk-methods/index.html b/frontend-integration/sdk/sdk-methods/index.html index 77ff8e1e..45266503 100644 --- a/frontend-integration/sdk/sdk-methods/index.html +++ b/frontend-integration/sdk/sdk-methods/index.html @@ -12,7 +12,7 @@ All methods | Lido on Solana - + @@ -52,7 +52,7 @@ accountsTotal: number, accountsEmpty: number, }>

    getMarketCap()

    Returns stSOL market cap in $

    Syntax:

    const marketCap = await solidoSDK.getMarketCap();

    console.log(`stSOL market cap $${marketCap}`); // $113174513

    Parameters:

    • totalStakedInSol? - total staked SOL-s

    Return value:

    type: Promise<number>

    getTotalRewards()

    Returns total rewards that benefited stSOL holders, in total, since we started tracking in SOL

    Syntax:

    const totalRewards = await solidoSDK.getTotalRewards();

    console.log(`Total Rewards $${totalRewards} SOL`);

    Parameters:

    • precision? - the number of digits to appear after the decimal point (default = 2)

    Return value:

    type: Promise<number>

    getLidoStatistics()

    Returns the united response of the previous functions (totalStaked, stakersCount, marketCap, also apy)

    Syntax:

    const { apy, totalStaked, stakers, marketCap, totalRewards } = await solidoSDK.getLidoStatistics();

    console.log(`Annual percentage yield: ${apy}%`);
    console.log(`Total staked with Lido: ${totalStaked.formatted}`);
    console.log(`Stakers: ${stakers.formatted}`);
    console.log(`stSOL market cap: $${marketCap}`);
    console.log(`Total Rewards $${totalRewards} SOL`);

    Return value type:

    Note: here will be max APY, if you want all periods, use getStakeApy

    Promise<{
    apy: number,
    totalStaked: {
    value: number,
    formatted: number,
    },
    stakers: {
    value: string,
    description: string,
    accountsTotal: number,
    accountsEmpty: number,
    formatted: string,
    },
    marketCap: number,
    totalRewards: {
    value: number,
    formatted: string,
    },
    }>
    Lido Statistics

    enum INSTRUCTION {
    STAKE = 1,
    UNSTAKE = 2,
    }
    - + \ No newline at end of file diff --git a/frontend-integration/sdk/stake/index.html b/frontend-integration/sdk/stake/index.html index d09fd095..df997ced 100644 --- a/frontend-integration/sdk/stake/index.html +++ b/frontend-integration/sdk/stake/index.html @@ -12,13 +12,13 @@ Staking & UnStaking | Lido on Solana - +

    Staking & UnStaking


    1. Initialize the library

    import { SolidoSDK } from '@lidofinance/solido-sdk';
    import { Connection } from '@solana/web3.js';

    // Change rpc endpoint to yours, or whole connection
    const connection = new Connection('https://test.rpcpool.com');

    const solidoSDK = new SolidoSDK('mainnet-beta', connection, 'your_solana_referral_address');

    2. Call stake method

    type SetTxStageCallback = (props: {
    txStage: TX_STAGE;
    transactionHash?: TransactionSignature; // for TX_STAGE.AWAITING_BLOCK stage
    deactivatingSolAccountAddress?: PublicKey; // for TX_STAGE.AWAITING_SIGNING stage unstake instructions
    stSolAccountAddress?: PublicKey; // for TX_STAGE.AWAITING_SIGNING stage stake instructions
    }) => void;


    try {
    const { transactionHash, stSolAccountAddress } = await solidoSDK.stake({
    amount: 20, // The amount of SOL-s which need to stake
    wallet: wallet, // Wallet instance
    setTxStage: setTxStageCallback, // Optional callback for getting information about transaction stage (see TX_STAGE)
    });
    } catch (e) {
    // Handle Errors
    }
    caution

    You may get an exception if amount exceed maximum available SOL-s in balance. In order to prevent this exception, you can call

    const maxStakeAmount = await solidoSDK.calculateMaxStakeAmount(new PublicKey(wallet.publicKey));

    Unstaking

    Unstaking process if whole the same as staking, also arguments are the same, just methods rename:

    • getStakeTransaction => getUnStakeTransaction
    • calculateMaxStakeAmount => calculateMaxUnStakeAmount
    • stake => unStake

    enum TX_STAGE {
    AWAITING_SIGNING = 1,
    AWAITING_BLOCK = 2,
    SUCCESS = 3,
    ERROR = 4,
    }
    - + \ No newline at end of file diff --git a/governance/index.html b/governance/index.html index 27f7f6a5..3f8e0e7b 100644 --- a/governance/index.html +++ b/governance/index.html @@ -12,7 +12,7 @@ Governance | Lido on Solana - + @@ -36,7 +36,7 @@ For example, the proposal to build Lido on Solana was accepted through a unanimous Snapshot vote in favor of the proposal. Before proposals are put up for voting, they are discussed on the Lido forum.

    - + \ No newline at end of file diff --git a/incentives/index.html b/incentives/index.html index c1400537..d7e98fb1 100644 --- a/incentives/index.html +++ b/incentives/index.html @@ -12,7 +12,7 @@ Incentives | Lido on Solana - + @@ -23,7 +23,7 @@ lists all past multisig transactions that funded these incentive programs.

    The table below is generated by the script print_incentive_history.py in the main repository.

    2021-12-15

    NameAmount (wLDO)Recipient wLDO accountRecipient owner accountMultisig transaction
    Mercurial stSOL-SOL40,00045GXyW…aRHT1HD7PY6T…rrgUXGFuoT4Y…6mAizJ
    Orca stSOL-USDC60,0008uGgbZ…xzvEwr2hLYdB…EiybPaJB92vL…7GQHD3
    Orca stSOL-wstETH10,000BEyEHj…AU4v9LHmcsoD…eabsjzFJTfrR…LZBhxH
    Raydium stSOL-USDC60,0008geEcD…qr1xs6DKSSeo…nzKxT42UtYtZ…2PkPtc

    2021-11-07

    NameAmount (wLDO)Recipient wLDO accountRecipient owner accountMultisig transaction
    Mercurial stSOL-SOL75,00045GXyW…aRHT1HD7PY6T…rrgUXG6a1K1e…Xgsud7
    Orca stSOL-wstETH125,000BEyEHj…AU4v9LHmcsoD…eabsjzDmfp4U…6DadZS
    Raydium stSOL-USDC125,0008geEcD…qr1xs6DKSSeo…nzKxT4ByJAsT…P2PgUz

    2021-10-06

    NameAmount (wLDO)Recipient wLDO accountRecipient owner accountMultisig transaction
    Mercurial stSOL-SOL75,00045GXyW…aRHT1HD7PY6T…rrgUXG7ymsoH…TY67gF
    Orca stSOL-wstETH125,000BEyEHj…AU4v9LHmcsoD…eabsjz5V1gUN…xWKkfY
    Raydium stSOL-USDC125,0008geEcD…qr1xs6DKSSeo…nzKxT46q6QgB…usTfyk
    - + \ No newline at end of file diff --git a/index.html b/index.html index 0b68b4d7..3e5f4a92 100644 --- a/index.html +++ b/index.html @@ -12,14 +12,14 @@ Lido on Solana was sunset | Lido on Solana - +
    - + \ No newline at end of file diff --git a/internals/commission/index.html b/internals/commission/index.html index e36449c9..9be7d2df 100644 --- a/internals/commission/index.html +++ b/internals/commission/index.html @@ -12,7 +12,7 @@ Commission | Lido on Solana - + @@ -55,7 +55,7 @@ validator. With this “pull-based” approach, the number of validators is no longer limited by the Solana account limit.

    The maintenance bot will perform this claiming step for all validators.

    - + \ No newline at end of file diff --git a/internals/exchange-rate/index.html b/internals/exchange-rate/index.html index b88486c5..b9538829 100644 --- a/internals/exchange-rate/index.html +++ b/internals/exchange-rate/index.html @@ -12,7 +12,7 @@ Exchange rate | Lido on Solana - + @@ -81,7 +81,7 @@ UpdateExchangeRate executes. This is not a problem: users could have deposited in epoch k1k - 1 anyway. For Solido, UpdateExchangeRate effectively defines the start of the new epoch.

    - + \ No newline at end of file diff --git a/internals/solana-staking/index.html b/internals/solana-staking/index.html index 69d92179..80df6e13 100644 --- a/internals/solana-staking/index.html +++ b/internals/solana-staking/index.html @@ -12,7 +12,7 @@ Staking on Solana | Lido on Solana - + @@ -55,7 +55,7 @@ account itself, or the validator that controls it. For traditional non-pooled validators, it is set to an address controlled by the validator, usually the vote account address itself.

    - + \ No newline at end of file diff --git a/internals/withdrawals/index.html b/internals/withdrawals/index.html index cfb9b297..c3d780ef 100644 --- a/internals/withdrawals/index.html +++ b/internals/withdrawals/index.html @@ -12,7 +12,7 @@ Withdrawals | Lido on Solana - + @@ -182,7 +182,7 @@ Stake on Solana is subject to a cooldown period. We move this problem to the user, by making withdrawals return an active stake account, so we don’t need to keep track of the cooldown.

    - + \ No newline at end of file diff --git a/manual-withdrawal/cli/index.html b/manual-withdrawal/cli/index.html index 193f1f7b..5b0cbbf4 100644 --- a/manual-withdrawal/cli/index.html +++ b/manual-withdrawal/cli/index.html @@ -12,7 +12,7 @@ with CLI | Lido on Solana - + @@ -20,8 +20,8 @@

    Manual withdraw with CLI

    1. Environment Setup

    We've prepared a CLI in Solido to simplify your workflow. You'll need to:

    1. Install Rust: Follow the instructions at Rust Installation.
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env"rustup override set 1.60.0
    1. Install Solana CLI v1.13.4: Visit Solana CLI Installation.
    sh -c "$(curl -sSfL https://release.solana.com/v1.13.4/install)"
    1. Install Solido CLI v2.0.0 from the official GitHub repository: -See Solido Releases.
    git clone --recurse-submodules -b V2.1 https://github.com/lidofinance/solido solido_v2
    cd solido_v2
    cargo build --release

    2. Transfer stSOL to Local Account

    ⚠️ Note: Our CLI can only work with local keys. Consider using a new account for withdrawals to keep your main wallet secure. The withdrawal operation will utilize the following:

    • SOL_ACCOUNT_PUBKEY: Public key of the local Solana account.
    • STSOL_ACCOUNT_PUBKEY: Public key of the child stSOL account from SOL_ACCOUNT_PUBKEY.
    • KEYPAIR_FILE: Local file containing the keypair from SOL_ACCOUNT_PUBKEY.
    • STAKE_ACCOUNT_PUBKEY: Public key of the child stake account from SOL_ACCOUNT_PUBKEY.
    1. Create a new local account:
    solana-keygen new --outfile ./local-keypair.json

    Remember the KEYPAIR_FILE path and SOL_ACCOUNT_PUBKEY from the output.

    1. Verify the new account with SOL_ACCOUNT_PUBKEY:
    solana balance SOL_ACCOUNT_PUBKEY
    1. Transfer stSOL to the local account using SOL_ACCOUNT_PUBKEY and note the transaction signature.

    2. Identify STSOL_ACCOUNT_PUBKEY:

    ⚠️ After transferring stSOL, a child account for stSOL is created under your local account. To proceed, locate this address by searching your transaction signature on Solscan and saving the Destination pubkey found under Instruction Details →#3 - Token Transfer.

    STSOL_ACCOUNT_PUBKEY

    3. Withdraw stSOL

    1. Execute the withdrawal to your stake account:
    ./target/release/solido --config ./solido_config.json --keypair-path KEYPAIR_FILE withdraw --amount-st-sol STSOL_AMOUNT

    Record the STAKE_ACCOUNT_PUBKEY for further steps.

    1. Deactivate the stake account:
    solana deactivate-stake STAKE_ACCOUNT_PUBKEY --fee-payer KEYPAIR_FILE

    ⚠️ Wait for the epoch to end (~1-2 days) for the stake account to become inactive. Check the epoch status on Solana Explorer.

    4. Transfer SOL to Main Account

    After the epoch ends, withdraw SOL from STAKE_ACCOUNT_PUBKEY to your main account, referred to as MAIN_ACCOUNT_PUBKEY.

    solana withdraw-stake **STAKE_ACCOUNT_PUBKEY** \
    **MAIN_ACCOUNT_PUBKEY** SOL_AMOUNT \
    --fee-payer **KEYPAIR_FILE**
    - +See Solido Releases.
    git clone --recurse-submodules -b V2.1 https://github.com/lidofinance/solido solido_v2
    cd solido_v2
    cargo build --release

    2. Transfer stSOL to Local Account

    ⚠️ Note: Our CLI can only work with local keys. Consider using a new account for withdrawals to keep your main wallet secure. The withdrawal operation will utilize the following:

    • SOL_ACCOUNT_PUBKEY: Public key of the local Solana account.
    • STSOL_ACCOUNT_PUBKEY: Public key of the child stSOL account from SOL_ACCOUNT_PUBKEY.
    • KEYPAIR_FILE: Local file containing the keypair from SOL_ACCOUNT_PUBKEY.
    • STAKE_ACCOUNT_PUBKEY: Public key of the child stake account from SOL_ACCOUNT_PUBKEY.
    1. Create a new local account:
    solana-keygen new --outfile ./local-keypair.json

    Remember the KEYPAIR_FILE path and SOL_ACCOUNT_PUBKEY from the output.

    1. Verify the new account with SOL_ACCOUNT_PUBKEY:
    solana balance SOL_ACCOUNT_PUBKEY
    1. Transfer stSOL to the local account using SOL_ACCOUNT_PUBKEY and note the transaction signature.

    2. Identify STSOL_ACCOUNT_PUBKEY:

    ⚠️ After transferring stSOL, a child account for stSOL is created under your local account. To proceed, locate this address by searching your transaction signature on Solscan and saving the Destination pubkey found under Instruction Details →#3 - Token Transfer.

    STSOL_ACCOUNT_PUBKEY

    3. Withdraw stSOL

    1. Execute the withdrawal to your stake account:
    ./target/release/solido --config ./solido_config.json --keypair-path KEYPAIR_FILE withdraw --amount-st-sol STSOL_AMOUNT

    Record the STAKE_ACCOUNT_PUBKEY for further steps.

    1. Deactivate the stake account:
    solana deactivate-stake STAKE_ACCOUNT_PUBKEY --keypair KEYPAIR_FILE

    ⚠️ Wait for the epoch to end (~1-2 days) for the stake account to become inactive. Check the epoch status on Solana Explorer.

    4. Transfer SOL to Main Account

    After the epoch ends, withdraw SOL from STAKE_ACCOUNT_PUBKEY to your main account, referred to as MAIN_ACCOUNT_PUBKEY.

    solana withdraw-stake **STAKE_ACCOUNT_PUBKEY** \
    **MAIN_ACCOUNT_PUBKEY** SOL_AMOUNT \
    --keypair **KEYPAIR_FILE**
    + \ No newline at end of file diff --git a/manual-withdrawal/self-hosted-widget/index.html b/manual-withdrawal/self-hosted-widget/index.html index e0dad77c..5003e1e8 100644 --- a/manual-withdrawal/self-hosted-widget/index.html +++ b/manual-withdrawal/self-hosted-widget/index.html @@ -12,14 +12,14 @@ with self-hosted widget | Lido on Solana - +

    Manual withdraw with self-hosted widget

    1. Local build

    Prerequisites

    • Node.js v18+
    • Yarn package manager

    This project requires an .env file which is distributed via private communication channels. A sample can be found in sample.env

    Development

    Step 1. Clone github repository stsol-unstake-widget

    git clone https://github.com/lidofinance/stsol-unstake-widget.git

    Step 2. Copy the contents of sample.env to .env.local

    cp sample.env .env.local

    Optinal: provide your-own private solana RPC endpoint

    For the best experience, set your own RPC endpoint (VITE_SOLANA_RPC_ENDPOINT)

    List of free services to get solana RPC endpoint

    Step 3. Install dependencies

    yarn install

    Step 4. Start the development server

    yarn dev

    Step 5. Open http://localhost:5173 with your browser to see the result.

    Step 6. Optional. Now you can build and deploy your own version of widget.

    - + \ No newline at end of file diff --git a/operation/maintenance/index.html b/operation/maintenance/index.html index 887438c4..2aca5412 100644 --- a/operation/maintenance/index.html +++ b/operation/maintenance/index.html @@ -12,7 +12,7 @@ Maintenance | Lido on Solana - + @@ -79,7 +79,7 @@ validator’s stSOL account; they are not paid into the account automatically by the on-chain program. To alleviate this, the maintenance bot will withdraw the rewards automatically for all validators, into their stSOL accounts.

    - + \ No newline at end of file diff --git a/operation/multisig-guide/index.html b/operation/multisig-guide/index.html index 63b41529..2feb70c6 100644 --- a/operation/multisig-guide/index.html +++ b/operation/multisig-guide/index.html @@ -12,7 +12,7 @@ Multisig guide | Lido on Solana - + @@ -33,7 +33,7 @@ approve the transactions:

    $ solido --config testnet.json multisig approve \
    --transaction-address BaVYNfiC8DkteXfJy58YcC5pz2qfYDBcNsAuEt7PBZ6h

    Transaction approved.
    Solana transaction id of approval: 2NKbP8LHYEy1DvZyq7gH2pHEDJk9E2f6Btv6sEeihzVpEi3qmBqbvs5SUKn3MaJCy6kEYQtyvCxSbkJea2LWawbj
    Multisig transaction now has 2 out of 4 required approvals.

    $ solido --config testnet.json multisig approve \
    --transaction-address Cq8MtYCYwep7s475yEaLWQbJr8wgnuSnW2Y5doaw6wf4

    Transaction approved.
    Solana transaction id of approval: 2RvvNVmqQnd4Fhf6jmac8xDiDADCXU1jVgaBvbrytiFPs2pvNq6LXgrGeeQbXCQqCbACaD5zqK8uCbsECrFiUwKD
    Multisig transaction now has 2 out of 4 required approvals.

    If the transaction is approved by a majority, you can also go ahead and execute it:

    $ solido --config testnet.json multisig execute-transaction \
    --transaction-address BaVYNfiC8DkteXfJy58YcC5pz2qfYDBcNsAuEt7PBZ6h

    Transaction executed.
    Solana transaction id of execution: 3qawwqtnb684gV9AgqoTqdx8pgZfGQ2dvmMxtfsYWXJgszDMKLP5BBbB4nZfmFwGK5dmFSoFGfSU5M7XSdmXavej

    $ solido --config testnet.json multisig execute-transaction \
    --transaction-address Cq8MtYCYwep7s475yEaLWQbJr8wgnuSnW2Y5doaw6wf4

    Transaction executed.
    Solana transaction id of execution: 5N9vgWmBec6BFmgnJqFe7zvB5TrS22vDcmPxSw2PoZj7WWHa4LDw4j14qfxywDXYTsUAeUUQCqSbGSh5tp2WqEJn
    note

    The multisig’s program derived address (PDA) needs to have sufficient funds to execute transactions. Lido team should have funded it during setup.

    You can confirm that the transaction was executed:

    $ solido --config testnet.json multisig show-transaction \
    --transaction-address Cq8MtYCYwep7s475yEaLWQbJr8wgnuSnW2Y5doaw6wf4

    Multisig: 7Yh1UgKE1KQoLYohynqdo84aNBwQ3GwU4XrCNY153PQ5
    Did execute: true

    Signers:
    [x] ENH1xvwjinUWkwEgw1hKduyAg7CrJMiKvr9nAS7wLHrp
    [x] DBd1yUhptC7yRq79sM4cAH1Zhe5rdTpJizxXJQGxRTyn
    [x] J4RLjzbJUrm4vRk5ZpPpk6CHzrmAiZGDByuyJ8f9jXR7
    [x] 6S21QCmpAadEhHj3pY2RMbPMGwgYNvS4Pd7zUXoRDMdK
    [ ] CeuSTdUx4XnPET4K4o3Zxx3zjh1yrR4f8fyWycGjs7wj
    [ ] 6DzkRQ3CJXMdnwm9aS2ww7KNeKxw3YLANzpUeTFoRCtC
    [ ] F4VFp4tFTyrQWo9YVjCbPE5eQP27ice2zyGDp2tN2Rkm

    (remaining output omitted)
    - + \ No newline at end of file diff --git a/operation/the-solido-utility/index.html b/operation/the-solido-utility/index.html index 39627cc8..6176658e 100644 --- a/operation/the-solido-utility/index.html +++ b/operation/the-solido-utility/index.html @@ -12,7 +12,7 @@ The Solido utility | Lido on Solana - + @@ -51,7 +51,7 @@ blind signing, you allow the Ledger to sign transactions that it cannot show a summary for. The Ledger still requires human confirmation to sign, even when blind signing is enabled.

    - + \ No newline at end of file diff --git a/overview/index.html b/overview/index.html index be4a87e8..69d69537 100644 --- a/overview/index.html +++ b/overview/index.html @@ -12,13 +12,13 @@ Overview | Lido on Solana - +

    Overview

    Lido on Solana

    'Lido on Solana' is a Lido-DAO governed liquid staking protocol for the Solana blockchain. Anyone who stakes their SOL tokens with Lido will be issued an on-chain representation of SOL staking position with Lido validators, called stSOL. We will work to integrate stSOL widely into the Solana DeFi ecosystem to enable stSOL users to make use of their staked assets in a variety of applications.

    Lido on Solana gives you:

    • Liquidity — No delegation/activation delays and the ability to sell your staked tokens
    • One-click staking — No complicated steps
    • Decentralized security — Assets spread across the industry’s leading validators chosen by the Lido DAO

    How Lido on Solana works

    Lido on Solana not only makes it very easy to stake but also provides further utility through stSOL. Let’s look at the process in slight detail. A SOL token holder connects their wallet to the Lido interface (hosted at https://solana.lido.fi) and deposits their tokens into the Lido program. They immediately receive stSOL tokens that represent a share of the total pool. Every user’s tokens are first held in a pool controlled by the Lido program.

    How Lido on Solana works

    The Lido program collects the deposited SOL and releases the newly minted stSOL to the user. Beneath the layer, the Lido Program will distribute this SOL uniformly across those validators that are participating. When these delegations accrue rewards on the allotted stake, the total SOL under management increases and this increases the value of stSOL tokens. The Lido DAO governs the Lido Program — and also controls the list of validators that are part of this program.

    - + \ No newline at end of file diff --git a/security/index.html b/security/index.html index 03096c40..c0efb419 100644 --- a/security/index.html +++ b/security/index.html @@ -12,7 +12,7 @@ Security | Lido on Solana - + @@ -31,7 +31,7 @@ members. See the administration page for more details about the multisig, and see the deployments page for the addresses of our deployments and the multisig members.

    - + \ No newline at end of file diff --git a/staking/Orca-pool-Wormhole-guide/index.html b/staking/Orca-pool-Wormhole-guide/index.html index 6d2461c3..cc915f17 100644 --- a/staking/Orca-pool-Wormhole-guide/index.html +++ b/staking/Orca-pool-Wormhole-guide/index.html @@ -12,7 +12,7 @@ Wormhole Transfer and Orca Pool Guide | Lido on Solana - + @@ -22,7 +22,7 @@ approved

    Once the approval is successful, again enter the same amount of tokens and click on Wrap. Once you sign the transaction in your wallet, your wallet balance will start reflecting wstETH tokens

    note

    If you enter a higher number to Wrap, than what you approved, you'll be shown the Unlock button again and you will have to approve this higher amount again. However, you can always wrap an amount lower than what you approved.

    wrap

    Step 3: Connect Ethereum wallet to Wormhole V2 Bridge

    Now that you have wstETH it is time to bridge them over to the Solana ecosystem. The first step in that direction is to visit the Wormhole Bridge. Under Source select Ethereum as the chain and click on Connect

    wormhole

    Your wallet screen will pop-up. Upon successful connection you should see your ERC-20 address on the Disconnect button.

    info

    This process of bridging your wstETH from Ethereum Blockchain to Solana, requires various transactions to be approved in your Ethereum wallet. Make sure you have enough Ethereum to pay for gas fee. In total these transactions can potentially cost roughly between $50-200 in gas fees depending on the conditions on the Ethereum mainnet.

    Step 4: Select Token Account - wstETH

    After connecting, scroll down to select wstETH in the Token account dropdown. It will display your wstETH balance

    wormhole-token-account

    Step 5: Enter the amount of wstETH to transfer and click on Next

    Unfortunately, you do not get the option to select MAX when filling this amount. So you have to manually type in the amount of wstETH that you need to transfer.

    wormhole-source-token-amount

    You will be immediately taken to the next step i.e. Target and the first step Source will show up as completed.

    Step 6: Connect Solana Wallet

    Under Target, select Solana and click on Select Wallet to connect to your Solana wallet.

    wormhole-solana-wallet

    note

    From this step onwards, certain transactions will happend on the Solana blockchain. You will need to hold some amount of SOL in your main account for fees (but of course much less than on Ethereum :))

    Step 7: Creating Associated Token Account

    Once the wallet is connected, your SOL address will start reflecting to the left of the Disconnect button. Every new token in the Solana ecosystem gets assigned an Associated Token Account. This account is automatically created for you once you click on the Create Associated Token Account

    wormhole-ata

    You will have to approve the creation of this account in your Solana wallet.

    wormhole-ata-approval

    Step 8: Send Tokens

    You can now send the tokens through Wormhole to the Solana blockchain.

    note

    It is generally not safe to approve unlimited tokens to be sent over Wormhole but if you envision yourself repeating this process multiple times, it might make sense for you to approve unlimited tokens to be transferred.

    wormhole-approve-send

    Approve the transaction in your Ethereum wallet

    wormhole-approve-send-wallet

    After successful approval, transfer the tokens.

    wormhole-transfer

    Once this transaction is executed successfully the Wormhole V2 bridge waits for 15 Ethereum confirmations (3-5 minutes) to bridge your token to the Solana blockchain.

    wormhole-15-confirmations wormhole-4-confirmations

    Step 9: Redeem Tokens

    Once 15 confirmations happen, you will be able to redeem the corresponding Solana token to your wallet. The Solana equivalent of the ERC-20 wstETH is also called wstETH.

    wormhole-redeem

    info

    You will be required to Approve multiple transactions to complete the token redemption process. Click on the Approve button every time the wallet screen pops up until the process is completed. You might have to approve 4-5 times.

    wormhole-multiple-approve

    tip

    If you are using Ledger to approve the Solana transactions, you will need to check the option Allow Blind Signing. So the process will be

    • Allow Blind Signatures
    • Click on Approve button on the screen
    • Finally, approve in the Ledger

    After successful approvals, you will finally see the following on the screen

    wormhole-success

    Step 10: Connect to the Orca Pool

    Congratulations! You are now the proud owner of wstETH on Solana!

    In case you do not have stSOL at this point head over to the following guides to stake your SOL and acquire some stSOL

    Assuming that you have both stSOL and wstETH you can now deposit these to the Orca Pool. Click on the link and scroll to (or search for stSOL) the stSOL-wstETH pool.

    Before you can deposit you need to connect Orca to your Solana wallet

    orca-connect

    Orca shows you your token balance as well.

    orca-token-balance

    Step 11: Deposit Tokens to the Orca Pool

    Finally, you may click on the Deposit button next to the pool and enter the amount of liquidity of stSOL and wstETH that you want to add.

    orca-deposit

    Alternatively, just click on the MAX amount next to either of the tokens and Orca app will pre-fill both the token values according to the prevailing exchange rate on the AMM.

    orca-max-wsteth

    After filling-in the amounts check the I verify checkbox and click on Deposit

    orca-deposit-click

    Approve the deposit transaction in the wallet and wait for the successfull completion of the transaction.

    orca-approve-deposit

    You've now successfully deposited both the tokens.

    orca-deposit-complete

    Step 12: Earn extra rewards from Orca Double-Dip

    Once you've deposited in the Orca Pool you will become eligible to earn further rewards through Orca Double Dipping. Go to the tab Double Dip, it should be right next to the Your Liquidity tab.

    orca-double-dip-tab

    Search for the stSOL-wstETH pool and click on Double-dip.

    orca-double-dip orca-double-dipping

    After you approve the double dipping transaction, you will see that you immediately start earning wLDO tokens as well. Sit back, relax and enjoy the rewards!

    orca-dip-success

    - + \ No newline at end of file diff --git a/staking/ledger/index.html b/staking/ledger/index.html index 27f9cd33..8a5c7a7c 100644 --- a/staking/ledger/index.html +++ b/staking/ledger/index.html @@ -12,7 +12,7 @@ Ledger | Lido on Solana - + @@ -21,7 +21,7 @@ Ready

    Step 2: Connect Ledger to Lido

    Once the Ledger is setup visit https://solana.lido.fi to stake your SOL tokens. Now connect your Ledger device to your machine and press the connect button in the top-right corner of the Lido interface.

    Connect

    Pressing the connect wallet button, on the top right hand corner of the screen, pops up the wallet screen.

    Wallet List

    Selecting Ledger and pressing the connect button pops up a dialog box for you to approve the connection. Make sure to verify the details (if any) listed on the approval dialog box by Ledger.

    Approve 1 Approve 2

    Once connected you would be able to see your balance on the Lido widget. Before you interact with the widget further it is important to explore the widget and understand its functionality.

    Step 2: Explore the interface

    At the top you can see your account’s information — your current stSOL balance and the number of SOL tokens available for staking. For new account holders, the staked amount (stSOL) will be 0 in the beginning. You can also see the returns you will get by staking with Lido under Lido APR. Below that you can enter the number of SOL you want to stake.

    Interface

    Account info

    You can go to the top-right corner of the screen and click on your connected account. This lets you take a look at your address and disconnect at any point during the process.

    To view the transaction history of your address on Solana's blockexplorer you can add your address to the end of the following URL

    https://solana.fm/address/**your-address-goes-here**

    Account Info Connect Dialog

    Transaction Parameters

    When you enter the amount of SOL you want to stake, the values below the submit button change automatically. These values give you specific information about the transaction you are about to perform. It tells you the

    • Exchange rate of SOL v/s stSOL at the moment
    • Amount of stSOL you will receive
    • Transaction cost
    • Fee that will be deducted for this transaction

    Transaction Params

    Lido Statistics

    Just below the transaction parameters you also see global Lido statistics. This gives you a clear idea of how much SOL is being staked worldwide and other information regarding the liquid staking ecosystem.

    Lido Params

    FAQs

    You can see the FAQ section right below the Lido statistics. It is prudent to familiarize yourself with some of the basic features of liquid staking and the risks involved. The FAQ section also gives more information about the stSOL and its value. In case, you have even more questions you can always reach out to the Lido on Solana team for any clarifications. The contact information is given at the end of this article.

    Faqs

    Step 3: Stake your SOL

    Stake

    To stake your SOL with lido enter the amount you want to stake. On the lido widget will see a pop-up showing the state of your transaction. The Lido widget waits for you to approve this transaction through your Ledger device.

    Note This transaction will only go through if you go back to Ledger and approve it.

    Staking

    You get additional information about the transaction details while approving the transaction. Go ahead and approve the transaction.

    Approve Transaction

    After verifying the information you can approve now.

    Step 4: View the transaction on Blockexplorer

    Once you hit approve on your wallet, you can come back to the lido widget and click on View on Solana Blockexplorer.

    View Tx

    This is useful as it tells you the current status of your transaction. In the block explorer, if you look at the Confirmations field you can slowly see it increasing from 0 to 32. Once it reaches the MAX number of confirmations your transaction gets added to the blockchain

    Finally after 32 confirmations, our transaction gets confirmed

    You can now go back to the Lido widget and look at your updated stSOL balance. Just below the stSOL balance, you will also be able to see the amount of SOL you can get back for it a.k.a the exchange rate.

    Update

    Zooming into the widget we can observe the new SOL balance and the updated stSOL balance

    Note 1: We had 2 SOL in the beginning and we staked 1 SOL. We should be left with 1 SOL but we had to pay an additional 0.0021 SOL as the rent for the new stSOL account that got created for us.

    Note 2: This rent is a one-time fee that won’t recur on the next staking transaction.

    Updated Balance

    Withdrawing Solana

    To withdraw click on the Unstake tab and enter the amount of stSOL that you would like to unstake in the field provided below.

    unstake-amount

    Then click unstake and head over to your wallet to approve the transaction.

    unstake-transaction

    The Solana blockchain waits for 32 confirmations (called MAX Confirmations) before making a transaction 'final'. Once the transaction gets the MAX Confirmations the Lido program splits off a stake account with the redeemed SOL amount and transfers it to you.

    unstake-successful

    You then unstake those SOL and will receive liquid SOL after the deactivation period which lasts for approximately 2 epochs. For users that desire instant liquidity, the preferred option is to exchange stSOL on the open market, e.g. on the supported AMM pools on Raydium.

    - + \ No newline at end of file diff --git a/staking/migrate-aux-to-ata-guide/index.html b/staking/migrate-aux-to-ata-guide/index.html index 8982b410..9e02e0ea 100644 --- a/staking/migrate-aux-to-ata-guide/index.html +++ b/staking/migrate-aux-to-ata-guide/index.html @@ -12,13 +12,13 @@ Migrating tokens from Aux account to ATA account | Lido on Solana - +

    Migrating tokens from Aux account to ATA account

    Associated Token Accounts v/s Aux Accounts

    Solana Program Library (SPL) allows a user to hold multiple tokens accounts corresponding to the same mint. These accounts

    • All have different addresses
    • Do not bear any relation with the user's main account address
    • Hold only those tokens which are produced by that specific mint

    Such accounts are known as Aux Accounts. However, these accounts can be a source of considerable confusion for other users trying to transfer money to the holder of the Aux Accounts. It also becomes nuanced for Dapps to build solutions that list a user's Aux Accounts.

    To overcome this problem Solana Program Library provides Associated Token Accounts (ATA) which are deterministically derived from the user's main account address and a token mint address. This makes it easier for wallets to keep track of all the ATAs corresponding to one user (one main System account address).

    Lido on Solana Aux Accounts

    Every time a user deposits into and subsequently withdraws from the Lido on Solana program they are provided with a deactivating stake account. In its early days these deactivating stake accounts were just Aux Accounts. Later on, the Lido program started creating Associated Token Accounts upon withdrawal. Users who performed withdrawals within the first few days of Lido on Solana launch were assigned the Aux accounts.

    note

    For more details about the withdrawal process and deactivating stake accounts please visit https://docs.solana.lido.fi/staking/phantom#step-6-unstaking-and-utlizing-stsol

    These users now need to migrate their Aux accounts to ATA as most wallets recognize the ATAs. Those who do not migrate to ATAs may face problems when depositing into pools. For example a user with stSOL in their Aux account tried to deposit into the Mercurial stSOL-2Pool but got a warning that their Transaction may fail to confirm

    Mercurial Error

    This warning and other errors may arise if stSOL lies in an Aux Account instead of an ATA.

    How to migrate to an ATA account

    1. Checking stSOL in Aux Account

    To check if your stSOL is not in an ATA head over to https://raydium.io/swap and connect your wallet.

    In case you have stSOL in an Aux Account Raydium will show you the following warning

    danger

    You have 1 Token Accounts in your wallet that need to be migrated to associated token accounts. To learn more click here or use this migration tool to simplify the process of migrating your balances

    Raydium Warning

    2. Migrating the Aux Account to ATA

    If you do have tokens in your Aux Account head over to https://v1.raydium.io/migrate/. You will see the Aux Account Address, the balance and the token that needs to be migrated - stSOL in this case.

    Raydium Migrate

    Click Migrate Token Accounts. Upon successful migration you will be able to deposit your stSOL easily into pools like Mercurial and Orca.

    - + \ No newline at end of file diff --git a/staking/overview/index.html b/staking/overview/index.html index 889a94e8..9525023e 100644 --- a/staking/overview/index.html +++ b/staking/overview/index.html @@ -12,7 +12,7 @@ Staking | Lido on Solana - + @@ -22,7 +22,7 @@ The accrued rewards here are after a fee cut for Lido maintainers. To incentivize sustainable management of the Lido ecosystem, a portion of the rewards is split between the node operators and DAO treasury. The remaining larger chunk (on Ethereum, these amount to 90%) of rewards accrue to Lido users and get reflected in the increased value of stSOL as explained above.

    Staking Rewards

    Lido on Solana doesn’t follow the pegging approach, followed by ETH and stETH, as of now. However, this might be considered for revision when Solana launches native support for rebasing in SPL tokens. Utilizing Liquidity The stSOLs that one gets can be used to reap secondary rewards through DeFi protocols. There will also be liquidity pools on AMM protocols and other DEXes where one will be able to immediately exchange stSOL for SOL. For the ETH<->stETH pair a popular AMM in terms of liquidity and volume is the Curve pool.

    - + \ No newline at end of file diff --git a/staking/phantom/index.html b/staking/phantom/index.html index 5eafaaa6..909c2add 100644 --- a/staking/phantom/index.html +++ b/staking/phantom/index.html @@ -12,7 +12,7 @@ Phantom | Lido on Solana - + @@ -23,7 +23,7 @@ The address for the demo account is

    Address - yBfu1AzbyRcfoJRU5TcUf59QwntqoFeDDTF9efh6XjL

    Blockexplorer URL - https://solana.fm/address/yBfu1AzbyRcfoJRU5TcUf59QwntqoFeDDTF9efh6XjL?cluster=testnet-qn1

    Its transaction history can be viewed on the blockexplorer here.

    Account Info

    Connect Dialog

    Transaction Parameters

    When you enter the amount of SOL you want to stake, the values below the submit button change automatically. These values give you specific information about the transaction you are about to perform. It tells you the

    • Exchange rate of SOL v/s stSOL at the moment
    • Amount of stSOL you will receive
    • Transaction cost
    • Fee that will be deducted for this transaction

    Transaction Params

    Lido Statistics

    Just below the transaction parameters you also see global Lido statistics. This gives you a clear idea of how much SOL is being staked worldwide and other information regarding the liquid staking ecosystem.

    Lido Params

    FAQs

    You can see the FAQ section right below the Lido statistics. It is prudent to familiarize yourself with some of the basic features of liquid staking and the risks involved. The FAQ section also gives more information about the stSOL and its value. In case, you have even more questions you can always reach out to the Lido on Solana team for any clarifications. The contact information is given at the end of this article.

    Faqs

    Step 4: Stake your SOL

    Stake

    To stake your SOL with lido enter the amount you wanter to stake. Once you submit you might get redirected to your wallet. On the lido widget will see a pop-up showing the state of your transaction. The Lido widget waits for you to approve this transaction through your wallet.

    Note This transaction will only go through if you go back to your wallet and approve it.

    Staking

    You get additional information about the transaction details while approving the transaction. Go ahead and approve the transaction.

    Approve

    After verifying the information you can approve now.

    Step 5: View the transaction on Blockexplorer

    Once you hit approve on your wallet, you can come back to the lido widget and click on View on Solana Blockexplorer.

    View Tx

    This is useful as it tells you the current status of your transaction.

    Link for the above transaction - https://solana.fm/tx/3jDcSYVRVUEyNfTVZ6T6WaddAKq24wyp5PapndbrzUQj2xbk3LAuSaTp4B2UAfseobQsTNaBsWaW5hzEqPwkyQKB?cluster=testnet-qn1

    If you look at the Confirmations field you can slowly see it increasing from 0 to 32. Once it reaches the MAX number of confirmations your transaction gets added to the blockchain

    Confirmations 1 Confirmations 2 Confirmations 3

    Finally after 32 confirmations, our transaction gets confirmed

    Confirmations 4

    You can now go back to the Lido widget and look at your updated stSOL balance. Just below the stSOL balance, you will also be able to see the amount of SOL you can get back for it a.k.a the exchange rate.

    Update

    Zooming into the widget we can observe the new SOL balance and the updated stSOL balance

    Note 1: We had 2 SOL in the beginning and we staked 1 SOL. We should be left with 1 SOL but we had to pay an additional 0.0021 SOL as the rent for the new stSOL account that got created for us.

    Note 2: This rent is a one-time fee that won’t reccur on the next staking transaction.

    Updated Balance

    Step 6: Unstaking and utlizing stSOL

    To withdraw click on the Unstake tab and enter the amount of stSOL that you would like to unstake in the field provided below.

    unstake-amount

    Then click unstake and head over to your wallet to approve the transaction.

    note

    Make sure to note down the transaction hash or the link provided on the screen. This allows for an easier debugging in case of a failed transaction.

    unstake-transaction

    The Solana blockchain waits for 32 confirmations (called MAX Confirmations) before making a transaction 'final'. Once the transaction gets the MAX Confirmations the Lido program splits off a stake account with the redeemed SOL amount and transfers it to you.

    note

    Make sure to note down the stake account address by clicking on the blockexplorer link provided on the screen.

    unstake-successful

    After unstaking go back to your wallet and click on the Solana token balance button.

    Click on Solana tokens section

    You will see the number of deactivating stake accounts. Click on the stake accounts button.

    note

    Note that the option to view deactivating stake accounts is visible only in Phantom and Solflare wallets. On Solong you will not be able to see these stake accounts. This is not a cause for concern as you can always migrate from Solong to either Phantom or Solflare for free

    Click on the stake accounts button

    You will then see your deactivating stake account where you can keep a track of your deactivating stake.

    Deactivating

    If you issue the unstake instruction when epoch N is going on, the deactivation will start immediately and your stake will completely deactivate at epoch N+1.

    For example, for the stake account shown in the example above the Unstake was done at epoch 225, the stake started deactivating within the same epoch and the SOL became available for withdrawing at epoch 226

    epochN+2

    After your stake gets completely deactivated you your stake accounts go from deactivating to inactive. You can then withdraw your SOL tokens by clicking on the three dots on the top right.

    Deactivated stake

    Withdraw your SOL

    For users who desire instant liquidity, the preferred option is to exchange stSOL on the open market, e.g. on the supported AMM pools Raydium.

    Utilizing and exchanging stSOL

    The following AMM pools and markets exist for exchanging stSOL or adding liquidity to pools.

    ProviderTypeLink
    OrcaSwap stSOL for SOL, USDC, USDThttps://www.orca.so/pools
    RaydiumSwap stSOL for USDCRaydium Pool
    - + \ No newline at end of file diff --git a/staking/solflare/index.html b/staking/solflare/index.html index f676b59f..48a953b6 100644 --- a/staking/solflare/index.html +++ b/staking/solflare/index.html @@ -12,7 +12,7 @@ Solflare | Lido on Solana - + @@ -28,7 +28,7 @@ Confirmation 2 Confirmation 3

    Finally, after 32 confirmations the transaction gets confirmed. The lido widget will reflect the new balance

    Confirmation 4

    You can now go back to the Lido widget and look at your updated stSOL balance. Just below the stSOL balance, you will also be able to see the amount of SOL you can get back for it a.k.a the exchange rate.

    Update Updated

    Note 1: We had 2 SOL in the beginning and we staked 1 SOL. We should be left with 1 SOL but we had to pay an additional 0.0021 SOL as the rent for the new stSOL account that got created for us.

    Note 2: This rent is a one-time fee that won’t reccur on the next staking transaction.

    Step 6: Unstaking and utlizing stSOL

    To withdraw click on the Unstake tab and enter the amount of stSOL that you would like to unstake in the field provided below.

    unstake-amount

    Then click unstake and head over to your wallet to approve the transaction.

    note

    Make sure to note down the transaction hash or the link provided on the screen. This allows for an easier debugging in case of a failed transaction.

    unstake-transaction

    The Solana blockchain waits for 32 confirmations (called MAX Confirmations) before making a transaction 'final'. Once the transaction gets the MAX Confirmations the Lido program splits off a stake account with the redeemed SOL amount and transfers it to you.

    note

    Make sure to note down the stake account address by clicking on the blockexplorer link provided on the screen.

    unstake-successful

    After unstaking go back to your wallet and click on the Staking tab in the solflare wallet.

    stakingtab

    You will see a number of deactivating stake accounts. Click to expand the staking account details.

    note

    Note that the option to view deactivating stake accounts is visible only in Phantom and Solflare wallets. On Solong you will not be able to see these stake accounts. This is not a cause for concern as you can always migrate from Solong to either Phantom or Solflare for free

    stake-accounts

    You will then see your deactivating stake account where you can keep a track of your deactivating stake. If you issue the unstake instruction when epoch N is going on, the deactivation will start immediately and your stake will completely deactivate at epoch N+1.

    For example, for the stake account shown in the example above the Unstake was done at epoch 225, the stake started deactivating within the same epoch and the SOL became available for withdrawing at epoch 226

    epochN+2

    After your stake gets completely deactivated, you will see that a Withdraw button appears below your stake account.

    Withdraw-Button

    You can withdraw your SOL by clicking on Withdraw. The SOL tokens should immediately reflect in your account. This complete process from first unstaking to finally withdrawing your stakes takes between 3-5 days to complete. For users who desire instant liquidity, the preferred option is to exchange stSOL on the open market, e.g. on the supported AMM pools on Raydium.

    Utilizing and exchanging stSOL

    The following AMM pools and markets exist for exchanging stSOL or adding liquidity to pools.

    ProviderTypeLink
    RaydiumSwap stSOL for USDCRaydium Pool
    - + \ No newline at end of file diff --git a/staking/solong/index.html b/staking/solong/index.html index 27a432af..04c77712 100644 --- a/staking/solong/index.html +++ b/staking/solong/index.html @@ -12,7 +12,7 @@ Solong | Lido on Solana - + @@ -31,7 +31,7 @@ Step8 Step9 Step10

    note

    Once you have migrated to Solflare you may visit the unstaking guide for Solflare to withdraw your SOL. The guide is present at https://docs.solana.lido.fi/staking/solflare

    Utilizing and exchanging stSOL

    The following AMM pools and markets exist for exchanging stSOL or adding liquidity to pools.

    ProviderTypeLink
    RaydiumSwap stSOL for USDCRaydium Pool
    - + \ No newline at end of file diff --git a/validator-onboarding/index.html b/validator-onboarding/index.html index ee6d2322..064f262c 100644 --- a/validator-onboarding/index.html +++ b/validator-onboarding/index.html @@ -12,7 +12,7 @@ Validator onboarding | Lido on Solana - + @@ -75,7 +75,7 @@ to add your vote account to the Solido instance, and the multisig members will batch-approve these transactions periodically.

    After your vote account has been added to the instance, the maintenance bot will automatically delegate new deposits to your vote account.

    - + \ No newline at end of file