Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.3.0 Release #9

Merged
merged 2 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# IDE/Tools
.docker
.idea
/.vscode
.vscode
# vim
.*.sw?

Expand All @@ -27,5 +27,8 @@ vendor/
# Cloud API key
.coinbase_cloud_api_key*.json

# Example binary
staking-client-*
# Example binaries
bin

# VSCode artifacts
**/__debug_bin**
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2018-2023 Coinbase, Inc.
Copyright (c) 2018-2024 Coinbase, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
305 changes: 249 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,263 @@
# Staking API Go Client Library
![Coinbase Staking API](docs/images/banner.svg)

This repository contains the Protocol Buffer definitions for the Coinbase **Staking API**, as well as the Go client libraries generated from them.
# [Coinbase Staking API](https://github.com/coinbase/staking-client-library-go)

> Programmatic access to Coinbase's best-in-class staking infrastructure and services. :large_blue_circle:

[![Current version](https://img.shields.io/github/tag/coinbase/staking-client-library-go?color=3498DB&label=version)](https://github.com/coinbase/staking-client-library-go/releases) [![GitHub contributors](https://img.shields.io/github/contributors/coinbase/staking-client-library-go?color=3498DB)](https://github.com/coinbase/staking-client-library-go/graphs/contributors) [![GitHub Stars](https://img.shields.io/github/stars/coinbase/staking-client-library-go.svg?color=3498DB)](https://github.com/coinbase/staking-client-library-go/stargazers) [![GitHub](https://img.shields.io/github/license/coinbase/staking-client-library-go?color=3498DB)](https://github.com/coinbase/staking-client-library-go/blob/main/LICENSE)

## Overview

Staking API provides a set of APIs to aid in non-custodial staking for multiple protocols and networks.
The **Coinbase Staking API** empowers developers to deliver a fully-featured staking experience in their Web2 apps, wallets, or dApps using *one common interface* across protocols.

# Documentation
A traditional infrastructure-heavy staking integration can take months. Coinbase's Staking API enables onboarding within hours by providing powerful and simple APIs on both sides of the staking experience.

In order to self-host the documentation run please use the swagger-ui docker container like so:
* [Orchestration](./protos/coinbase/staking/orchestration/v1): *Write*. Power non-custodial staking workflows for your users.

```bash
docker run -p 8080:8080 -e SWAGGER_JSON=/doc/coinbase/staking/v1alpha1/api.swagger.json -v $(PWD)/doc/openapi:/doc swaggerapi/swagger-ui
```
* [Rewards](./protos/coinbase/staking/rewards/v1): *Read*. Access onchain, staking-related rewards data.

## Quick Start

1. Create and download an API key from the [Cloud Platform](https://portal.cloud.coinbase.com/access/api).
2. Place the key named `.coinbase_cloud_api_key.json` at the root of this repository.
3. Run one of the code samples [below](#stake-partial-eth-💠) or any of our [provided examples](./examples/) :rocket:.

### Stake Partial ETH :diamond_shape_with_a_dot_inside:

This code sample creates an ETH staking workflow. View the full code sample [here](examples/ethereum/create-workflow/main.go)

<details open>
<summary>Code Sample</summary>

```golang
// examples/ethereum/create-workflow/main.go
package main

import (
"context"
"fmt"
"log"

## Prerequisites
"github.cbhq.net/cloud/staking-client-library-go/auth"
"github.cbhq.net/cloud/staking-client-library-go/client"
"github.cbhq.net/cloud/staking-client-library-go/client/options"
stakingpb "github.cbhq.net/cloud/staking-client-library-go/gen/go/coinbase/staking/orchestration/v1"
)

- [Golang 1.19+](https://go.dev/learn/)
func main() {
// TODO: Add your project ID found at cloud.coinbase.com or in your API key.
projectID := ""

## Repository Structure
- [`auth/`](./auth/) contains the authentication-related code for accessing Coinbase Cloud APIs.
- [`client/`](./client/) contains client instantiation helpers for Staking APIs.
- [`gen/`](./gen/) contains Go code generated from the Protocol Buffers.
- [`protos/`](./protos/) contains the Protocol Buffers that define the Staking APIs.
ctx := context.Background()

## Module Installation
// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

// Creates the Coinbase Staking API client.
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}

// Constructs the API request
req := &stakingpb.CreateWorkflowRequest{
Parent: fmt.Sprintf("projects/%s", projectID),
Workflow: &stakingpb.Workflow{
Action: "protocols/ethereum_kiln/networks/holesky/actions/stake",
StakingParameters: &stakingpb.Workflow_EthereumKilnStakingParameters{
EthereumKilnStakingParameters: &stakingpb.EthereumKilnStakingParameters{
Parameters: &stakingpb.EthereumKilnStakingParameters_StakeParameters{
StakeParameters: &stakingpb.EthereumKilnStakeParameters{
StakerAddress: "0xdb816889F2a7362EF242E5a717dfD5B38Ae849FE",
IntegratorContractAddress: "0xA55416de5DE61A0AC1aa8970a280E04388B1dE4b",
Amount: &stakingpb.Amount{
Value: "20",
Currency: "ETH",
},
},
},
},
},
SkipBroadcast: true,
},
}

workflow, err := stakingClient.Orchestration.CreateWorkflow(ctx, req)
if err != nil {
log.Fatalf("couldn't create workflow: %s", err.Error())
}

log.Printf("Workflow created: %s", workflow.Name)
}
```
go get github.com/coinbase/staking-client-library-go

</details>

<details>
<summary>Output</summary>

```text
2024/03/28 11:43:49 Workflow created: projects/62376b2f-3f24-42c9-9025-d576a3c06d6f/workflows/ffbf9b45-c57b-49cb-a4d5-fdab66d8cb25
```

</details>

### View Ethereum Rewards :moneybag:

This code sample returns rewards for an Ethereum validator address. View the full code sample [here](examples/ethereum/list-rewards/main.go).

<details open>
<summary>Code Sample</summary>

```golang
// examples/ethereum/list-rewards/main.go
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"time"

"google.golang.org/api/iterator"

"github.cbhq.net/cloud/staking-client-library-go/auth"
"github.cbhq.net/cloud/staking-client-library-go/client"
"github.cbhq.net/cloud/staking-client-library-go/client/options"
rewardsV1 "github.cbhq.net/cloud/staking-client-library-go/client/rewards/v1"
rewardspb "github.cbhq.net/cloud/staking-client-library-go/gen/go/coinbase/staking/rewards/v1"
)

func main() {
ctx := context.Background()

// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

// Creates the Coinbase Staking API client.
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}

// Lists the rewards for the given address for the previous last 2 days, aggregated by day.
rewardsIter := stakingClient.Rewards.ListRewards(ctx, &rewardspb.ListRewardsRequest{
Parent: rewardspb.ProtocolResourceName{Protocol: "ethereum"}.String(),
PageSize: 200,
Filter: rewardsV1.WithAddress().Eq("0xac53512c39d0081ca4437c285305eb423f474e6153693c12fbba4a3df78bcaa3422b31d800c5bea71c1b017168a60474").
And(rewardsV1.WithPeriodEndTime().Gte(time.Now().AddDate(0, 0, -2))).
And(rewardsV1.WithPeriodEndTime().Lt(time.Now())).String(),
})

// Iterates through the rewards and print them.
for {
reward, err := rewardsIter.Next()
if errors.Is(err, iterator.Done) {
break
}

if err != nil {
log.Fatalf("error listing rewards: %s", err.Error())
}

marshaled, err := json.MarshalIndent(reward, "", " ")
if err != nil {
log.Fatalf("error marshaling reward: %s", err.Error())
}

fmt.Printf(string(marshaled))
}
}
```

## Get Started
To test that your API Key gives you access as expected to the Staking APIs:

1. Clone this GitHub repo
2. Download your API key from the Coinbase Cloud UI and save it as `.coinbase_cloud_api_key.json` at the root of this repo
3. Run `go run examples/example.go`
4. You should see output like the following:
```
2023/09/25 15:01:03 got protocol: protocols/ethereum_kiln
2023/09/25 15:01:04 got network: protocols/ethereum_kiln/networks/mainnet
2023/09/25 15:01:04 got action: protocols/ethereum_kiln/networks/goerli/actions/stake
2023/09/25 15:01:04 got action: protocols/ethereum_kiln/networks/goerli/actions/unstake
2023/09/25 15:01:04 got action: protocols/ethereum_kiln/networks/goerli/actions/claim_rewards
```
### Create an Ethereum Kiln workflow
To test creating an Ethereum Kiln workflow perform the following:

1. Open `examples/ethereum_kiln/example.go` and set the following variables:
* `projectID` - this is the project ID of your Coinbase Cloud project
* `privateKey` - this is the private key of the address with this you want to perform staking actions
* `stakerAddress` - this is the address with which you want to perform staking actions
* `integratorContractAddress` - this is the integrator contract address to which you want to stake. This is typically procured by engaging with the Coinbase Cloud sales team.
2. Run `go run examples/ethereum_kiln/example.go`

### Create a Polygon workflow
To test creating a Polygon workflow perform the following:

1. Open `examples/polygon/example.go` and set the following variables:
* `projectID` - this is the project ID of your Coinbase Cloud project
* `privateKey` - this is the private key of the address with this you want to perform staking actions
* `delegatorAddress` - this is the address with which you want to perform staking actions
2. Run `go run examples/polygon/example.go`

### Listing workflows
To test listing workflows within a project, perform the following:

1. Open `examples/example_list_workflows.go` and set the following variables:
* `projectID` - this is the project ID of your Coinbase Cloud project
2. Run `go run examples/example_list_workflows.go`
</details>

<details>
<summary>Output</summary>

```json
{
"address": "0xac53512c39d0081ca4437c285305eb423f474e6153693c12fbba4a3df78bcaa3422b31d800c5bea71c1b017168a60474",
"period_identifier": {
"date": "2024-03-26"
},
"aggregation_unit": 2,
"period_start_time": {
"seconds": 1711411200
},
"period_end_time": {
"seconds": 1711497599
},
"total_earned_native_unit": {
"amount": "0.00211503",
"exp": "18",
"ticker": "ETH",
"raw_numeric": "2115030000000000"
},
"total_earned_usd": [
{
"source": 1,
"conversion_time": {
"seconds": 1711498140
},
"amount": {
"amount": "7.58",
"exp": "2",
"ticker": "USD",
"raw_numeric": "758"
},
"conversion_price": "3582.979980"
}
],
"protocol": "ethereum"
}
{
"address": "0xac53512c39d0081ca4437c285305eb423f474e6153693c12fbba4a3df78bcaa3422b31d800c5bea71c1b017168a60474",
"period_identifier": {
"date": "2024-03-27"
},
"aggregation_unit": 2,
"period_start_time": {
"seconds": 1711497600
},
"period_end_time": {
"seconds": 1711583999
},
"total_earned_native_unit": {
"amount": "0.002034193",
"exp": "18",
"ticker": "ETH",
"raw_numeric": "2034193000000000"
},
"total_earned_usd": [
{
"source": 1,
"conversion_time": {
"seconds": 1711584540
},
"amount": {
"amount": "7.13",
"exp": "2",
"ticker": "USD",
"raw_numeric": "713"
},
"conversion_price": "3504.580078"
}
],
"protocol": "ethereum"
}
```

</details>

## Documentation

There are numerous examples in the [`examples directory`](./examples) to help get you started. For even more, refer to our [documentation website](https://docs.cloud.coinbase.com/) for detailed definitions, API specifications, integration guides, and more!
36 changes: 36 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package client

import (
"context"
"fmt"

"github.com/coinbase/staking-client-library-go/client/options"
orchestrationClient "github.com/coinbase/staking-client-library-go/client/orchestration/v1"
rewardsClient "github.com/coinbase/staking-client-library-go/client/rewards/v1"
)

type StakingClient struct {
Orchestration *orchestrationClient.OrchestrationServiceClient
Rewards *rewardsClient.RewardsServiceClient
}

// New returns a StakingClient based on the given inputs.
func New(
ctx context.Context,
stakingOpts ...options.StakingClientOption,
) (*StakingClient, error) {
orchestrationClient, err := orchestrationClient.NewOrchestrationServiceClient(ctx, stakingOpts...)
if err != nil {
return nil, fmt.Errorf("failed to create orchestration client: %w", err)
}

rewardsClient, err := rewardsClient.NewRewardsServiceClient(ctx, stakingOpts...)
if err != nil {
return nil, fmt.Errorf("failed to create rewards client: %w", err)
}

return &StakingClient{
Orchestration: orchestrationClient,
Rewards: rewardsClient,
}, nil
}
Loading