Skip to content

Commit

Permalink
feat(SOLNENG-27): add solana buildervault nodejs staking example
Browse files Browse the repository at this point in the history
  • Loading branch information
MnrGreg committed Jul 25, 2024
1 parent 05f238e commit 16269ce
Show file tree
Hide file tree
Showing 18 changed files with 2,914 additions and 60 deletions.
16 changes: 16 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"image": "mcr.microsoft.com/devcontainers/universal:2.11.2",
//"forwardPorts": [3000],
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"markdown.showPreview",
"bierner.markdown-mermaid",
"aaron-bond.better-comments",
"ms-vscode.go"
]
}
}
}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
*.crt
*.key
.vscode
init
init
**/key.txt
**/.env
**/node_modules
62 changes: 8 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,12 @@
# Blockdaemon Staking API demos using different wallets and SDKs

## Sample go staking app demo
This repository contains multiple applications. Below are the links to the individual application folders and their README files.
To get started, click on the links for installation and usage instructions.

## Solana Staking
- [Stake deposit from Builder Vault wallet with TypeScript SDK](./solana-staking/buildervault-wallet/nodejs/README.md)

```mermaid
sequenceDiagram
autonumber
participant StakeClient as Sample stake<br> client application
participant StakeAPI as Stake Intent API
participant Blockchain as Blockchain RPC API
box Builder Vault
participant TSM1 as MPC Wallet <br>(private key share 1)
participant TSM2 as MPC Wallet <br>(private key share 2)
end
## Ethereum Staking
- [Stake deposit from Builder Vault wallet with Golang SDK](./ethereum-staking/buildervault-wallet/golang/README.md)
- [Stake deposit from Builder Vault wallet with TypeScript SDK](./ethereum-staking/buildervault-wallet/nodejs/README.md)

StakeClient ->> StakeAPI: get StakeIntent unsigned tx data <br>(amount, withdrawal & recipient address)
StakeClient ->> Blockchain: get blockchain inputs (gas, nonce) for new tx<br>(sender wallet)
StakeClient ->> StakeClient: construct unsigned tx
StakeClient ->> TSM1: request signature (unsigned tx)
TSM1 -->> StakeClient: return partial signature
StakeClient ->> TSM2: request signature (unsigned tx)
TSM2 -->> StakeClient: return partial signature
StakeClient ->> StakeClient: combine partial signatures
StakeClient ->> Blockchain: broadcast signed tx<br>(signed tx, deposit contract)
```

<!--
# Get Plans
http -b GET https://svc.blockdaemon.com/boss/v1/plans \
X-API-KEY:$STAKE_API_KEY
# Post Intent
http -b POST https://svc.blockdaemon.com/boss/v1/ethereum/holesky/stake-intents \
X-API-KEY:$STAKE_API_KEY \
accept:application/json \
content-type:application/json \
stakes:='[{"amount":"32000000000","withdrawal_address":"0x00000000219ab540356cBB839Cbe05303d7705Fa","fee_recipient":"0x93247f2209abcacf57b75a51dafae777f9dd38bc"}]'
# Get Intents
http -b GET https://svc.blockdaemon.com/boss/v1/stake-intents?protocols=ethereum&networks=holesky \
X-API-KEY:$STAKE_API_KEY
```
sequenceDiagram
autonumber
participant StakeClient as Sample stake<br> client application
participant StakeAPI as Stake Intent API
participant Blockchain as Blockchain
participant TSM as Sender Wallet Vault<br>(private key)
StakeClient ->> StakeAPI: get StakeIntent unsigned tx data <br>(amount, withdrawal & recipient address)
StakeClient ->> Blockchain: get blockchain inputs for new tx<br>(gas fee, chainID, sender wallet nonce)
StakeClient ->> StakeClient: construct unsigned tx
StakeClient ->> TSM: request signature of unsigned tx
TSM ->> StakeClient: return tx signature
StakeClient ->> Blockchain: broadcast signed tx<br>(signed tx, deposit contract)
--!>
58 changes: 58 additions & 0 deletions ethereum-staking/buildervault-wallet/golang/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

## Sample go staking app demo


```mermaid
sequenceDiagram
autonumber
participant StakeClient as Sample stake<br> client application
participant StakeAPI as Stake Intent API
participant Blockchain as Blockchain RPC API
box Builder Vault
participant TSM1 as MPC Wallet <br>(private key share 1)
participant TSM2 as MPC Wallet <br>(private key share 2)
end
StakeClient ->> StakeAPI: get StakeIntent unsigned tx data <br>(amount, withdrawal & recipient address)
StakeClient ->> Blockchain: get blockchain inputs (gas, nonce) for new tx<br>(sender wallet)
StakeClient ->> StakeClient: construct unsigned tx
StakeClient ->> TSM1: request signature (unsigned tx)
TSM1 -->> StakeClient: return partial signature
StakeClient ->> TSM2: request signature (unsigned tx)
TSM2 -->> StakeClient: return partial signature
StakeClient ->> StakeClient: combine partial signatures
StakeClient ->> Blockchain: broadcast signed tx<br>(signed tx, deposit contract)
```

<!--
# Get Plans
http -b GET https://svc.blockdaemon.com/boss/v1/plans \
X-API-KEY:$STAKE_API_KEY
# Post Intent
http -b POST https://svc.blockdaemon.com/boss/v1/ethereum/holesky/stake-intents \
X-API-KEY:$STAKE_API_KEY \
accept:application/json \
content-type:application/json \
stakes:='[{"amount":"32000000000","withdrawal_address":"0x00000000219ab540356cBB839Cbe05303d7705Fa","fee_recipient":"0x93247f2209abcacf57b75a51dafae777f9dd38bc"}]'
# Get Intents
http -b GET https://svc.blockdaemon.com/boss/v1/stake-intents?protocols=ethereum&networks=holesky \
X-API-KEY:$STAKE_API_KEY
```
sequenceDiagram
autonumber
participant StakeClient as Sample stake<br> client application
participant StakeAPI as Stake Intent API
participant Blockchain as Blockchain
participant TSM as Sender Wallet Vault<br>(private key)
StakeClient ->> StakeAPI: get StakeIntent unsigned tx data <br>(amount, withdrawal & recipient address)
StakeClient ->> Blockchain: get blockchain inputs for new tx<br>(gas fee, chainID, sender wallet nonce)
StakeClient ->> StakeClient: construct unsigned tx
StakeClient ->> TSM: request signature of unsigned tx
TSM ->> StakeClient: return tx signature
StakeClient ->> Blockchain: broadcast signed tx<br>(signed tx, deposit contract)
--!>
File renamed without changes.
File renamed without changes.
15 changes: 10 additions & 5 deletions main.go → ...taking/buildervault-wallet/golang/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"gitlab.com/Blockdaemon/go-tsm-sdkv2/tsm" // Builder Vault MPC SDK for wallet management
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -129,7 +128,13 @@ func craftTx(client *ethclient.Client, ethereumSenderAddress string, contractAdd
Data: common.FromHex(txData),
})

fmt.Println("\nCrafted unsigned transaction:\n", "Nonce:", unsignedTx.Nonce(), "\n GasFeeCap:", unsignedTx.GasFeeCap(), "\n Gas:", unsignedTx.Gas(), "\n To:", unsignedTx.To().String(), "\n Value:", unsignedTx.Value())
fmt.Println("\nCrafted unsigned transaction values:\n", "Nonce:", unsignedTx.Nonce(), "\n GasFeeCap:", unsignedTx.GasFeeCap(), "\n Gas:", unsignedTx.Gas(), "\n To:", unsignedTx.To().String(), "\n Value amount:", unsignedTx.Value(), "\n Hash:", unsignedTx.Hash())

raw, err := unsignedTx.MarshalBinary()
if err != nil {
panic(err)
}
fmt.Printf("\nCrafted unsigned transaction (hex encoded): 0x%x", raw)

// create a NewLondonSigner for EIP 1559 transactions
signer := types.NewLondonSigner(chainID)
Expand Down Expand Up @@ -193,7 +198,7 @@ func signTx(unsignedTxHash []byte) []byte {
copy(sigBytes[0:32], signature.R())
copy(sigBytes[32:64], signature.S())
sigBytes[64] = byte(signature.RecoveryID())
fmt.Println("\nTransaction signature:\n", hex.EncodeToString(sigBytes))
fmt.Println("\n\nTransaction signature (hex encoded):\n", hex.EncodeToString(sigBytes))

return sigBytes
}
Expand All @@ -206,11 +211,11 @@ func sendTx(client *ethclient.Client, chainID *big.Int, unsignedTx *types.Transa
panic(err)
}

raw, err := rlp.EncodeToBytes(signedTx)
raw, err := signedTx.MarshalBinary()
if err != nil {
panic(err)
}
fmt.Printf("\nSigned raw transaction: 0x%x", raw)
fmt.Printf("\nSigned raw transaction (RLP encoded): 0x%x", raw)

err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions ethereum-staking/buildervault-wallet/nodejs/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Blockdaemon Stake
BLOCKDAEMON_API_KEY=
BLOCKDAEMON_STAKE_API_KEY=
ETHEREUM_NETWORK=holesky # mainnet | holesky
ETHEREUM_WITHDRAWAL_ADDRESS=
PLAN_ID= # Optional. If provided, will use a specific validator plan.
66 changes: 66 additions & 0 deletions ethereum-staking/buildervault-wallet/nodejs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

# Ethereum staking on Testnet with Builder Vault wallet

```mermaid
sequenceDiagram
autonumber
participant StakeClient as Sample stake<br> client application
participant StakeAPI as Stake Intent API
participant Blockchain as Blockchain RPC API
box Builder Vault
participant TSM1 as MPC Wallet <br>(private key share 1)
participant TSM2 as MPC Wallet <br>(private key share 2)
end
StakeClient ->> StakeAPI: get StakeIntent unsigned tx data <br>(amount, withdrawal & recipient address)
StakeClient ->> Blockchain: get blockchain inputs (gas, nonce) for new tx<br>(sender wallet)
StakeClient ->> StakeClient: construct unsigned tx
StakeClient ->> TSM1: request signature (unsigned tx)
TSM1 -->> StakeClient: return partial signature
StakeClient ->> TSM2: request signature (unsigned tx)
TSM2 -->> StakeClient: return partial signature
StakeClient ->> StakeClient: combine partial signatures
StakeClient ->> Blockchain: broadcast signed tx<br>(signed tx, deposit contract)
```

### Prerequisites
- [Node.js](https://nodejs.org/en/download/package-manager) or use [code-spaces](https://codespaces.new/Blockdaemon/demo-buildervault-stakingAPI?quickstart=1)
- Register for a demo Builder Vault tenant: https://www.blockdaemon.com/get-started/builder-vault-sandbox-registration
- Download SDK bundle provided in registration email (extract authentication certificates)
- Place Builder Vault authentication certificate key-pair `client.crt` & `client.key` in this nodejs folder
- Register for free Blockdaemon [RPC API key](https://docs.blockdaemon.com/reference/get-started-rpc#step-1-sign-up-for-an-api-key) and set in .env as BLOCKDAEMON_API_KEY
- Register for free Blockdaemon [Staking API key](https://docs.blockdaemon.com/reference/get-started-staking-api#step-1-sign-up-for-an-api-key) and set in .env as BLOCKDAEMON_STAKE_API_KEY
- Speak to your CSM about getting credentials to the Blockdaemon nexus.sepior.net repo for the nodejs SDK.

### Step 1. Set environment variables in .env
```shell
cd ethereum-staking/buildervault-wallet/nodejs/
cp .env.example .env
```
- update .env with API keys

### Step 2. Install package dependancies
- replace NEXUS_USERNAME & NEXUS_PASSWORD with credential provided by your CSM
```shell
npm config set @sepior:registry=https://nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/
npm config set //nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/:username=NEXUS_USERNAME
npm config set //nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/:\_password=`echo -n 'NEXUS_PASSWORD' | base64`
npm install
```

### Step 3. Launch ethereum-stake-bv.ts to auto-create the Builder Vault wallet address on first run
```shell
npm run start ethereum-stake-bv.ts
```
- note, on first run this step will fail as the wallet address has no funds
- copy the new Ethereum wallet address and fund the account

### Step 4. Fund the new Ethereum wallet address with 33 ETH using faucets below
- https://holesky-faucet.pk910.de/#/

### Step 5. Launch ethereum-stake-bv.ts to generate the Stake Intent request, sign the request with BuilderVault and broadcast the transaction
```shell
npm run start ethereum-stake-bv.ts
```
- (optional) decode the raw unsigned transaction to inspect the Blockdaemon provided attributes (https://rawtxdecode.in)
- observe the confirmed transaction through the generated blockexplorer link
Loading

0 comments on commit 16269ce

Please sign in to comment.