-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from coinbase/feature/add-staking-orchestration
Feature add staking orchestration bones
- Loading branch information
Showing
10 changed files
with
287 additions
and
16 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"math/big" | ||
|
||
"github.com/coinbase/coinbase-sdk-go/pkg/coinbase" | ||
) | ||
|
||
func main() { | ||
client, err := coinbase.NewClient( | ||
coinbase.WithAPIKeyFromJSON("api_key.json"), | ||
) | ||
if err != nil { | ||
log.Fatalf("error creating coinbase client: %v", err) | ||
} | ||
address := client.NewAddress("ethereum-holesky", "0x57a063e1df096aaA6b2068C3C7FE6Ac4BC3c4F58") | ||
op, err := address.BuildStakeOperaiton(context.Background(), "eth", big.NewFloat(0.0001)) | ||
if err != nil { | ||
log.Fatalf("error building staking operation: %v", err) | ||
} | ||
|
||
log.Printf("staking operation ID: %s\n", op.ID()) | ||
log.Printf("staking operation Transactions: %+v\n", op.Transactions()) | ||
// | ||
address := coinbase.NewAddress("ethereum-holesky", "0x57a063e1df096aaA6b2068C3C7FE6Ac4BC3c4F58") | ||
op, err := client.BuildStakeOperation( | ||
context.Background(), | ||
&coinbase.BuildStakeOperationRequest{ | ||
Address: address, | ||
AssetId: "eth", | ||
Amount: big.NewFloat(0.0001), | ||
Options: map[string]string{ | ||
"mode": "default", | ||
} | ||
} | ||
) | ||
rewardsIter, err := client.ListStakingRewards( | ||
ctx, []coinbase.Address{address}, "eth", time.Now().Add(-time.Hour*24*7), time.Now(), | ||
coinbase.WithStakingRewardsLimit(100), | ||
coinbase.WithStakingRewardsPageOffset(2), | ||
) | ||
if err != nil { | ||
log.Fatalf("error building staking operation: %v", err) | ||
} | ||
|
||
log.Printf("staking operation ID: %s\n", op.ID()) | ||
log.Printf("staking operation Transactions: %+v\n", op.Transactions()) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package coinbase | ||
package auth | ||
|
||
import ( | ||
"encoding/json" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package coinbase | ||
package auth | ||
|
||
import ( | ||
"crypto/rand" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package coinbase | ||
|
||
type Address struct { | ||
NetworkID string `json:"network_id"` | ||
ID string `json:"id"` | ||
} | ||
|
||
func NewAddress(networkID string, ID string) *Address { | ||
return &Address{ | ||
NetworkID: networkID, | ||
ID: ID, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package coinbase | ||
|
||
import ( | ||
"context" | ||
"crypto/ecdsa" | ||
"math/big" | ||
|
||
"github.com/coinbase/coinbase-sdk-go/gen/client" | ||
) | ||
|
||
// StakeingOperationOption allows for the passing of custom options to | ||
// the staking operation, like `mode` or `withdrawal_address`. | ||
type StakingOperationOption func(*client.BuildStakingOperationRequest) | ||
|
||
// WithStakingOperationMode allows for the setting of the mode of | ||
// the staking operation (ie. `default`, `partial`, or `native`) | ||
func WithStakingOperationMode(mode string) StakingOperationOption { | ||
return WithStakingOperationOption("mode", mode) | ||
} | ||
|
||
// WithStakingOperationOption allows for the passing of custom options | ||
// to the staking operation, like `mode` or `withdrawal_address`. | ||
func WithStakingOperationOption(optionKey string, optionValue string) StakingOperationOption { | ||
return func(op *client.BuildStakingOperationRequest) { | ||
op.Options[optionKey] = optionValue | ||
} | ||
} | ||
|
||
// BuildStakingOperation will build an ephemeral staking operation based on | ||
// the passed address, assetID, action, and amount. | ||
func (c *Client) BuildStakingOperation( | ||
ctx context.Context, | ||
address *Address, | ||
assetID string, | ||
action string, | ||
amount *big.Float, | ||
o ...StakingOperationOption, | ||
) (*StakingOperation, error) { | ||
req := client.BuildStakingOperationRequest{ | ||
NetworkId: address.NetworkID, | ||
AssetId: assetID, | ||
AddressId: address.ID, | ||
Action: action, | ||
Options: map[string]string{ | ||
"mode": "default", | ||
"amount": amount.String(), | ||
}, | ||
} | ||
for _, f := range o { | ||
f(&req) | ||
} | ||
op, _, err := c.client.StakeAPI.BuildStakingOperation(ctx).BuildStakingOperationRequest(req).Execute() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return newStakingOperationFromModel(op), nil | ||
} | ||
|
||
// BuildStakeOperation will build an ephemeral staking operation using the | ||
// stake action | ||
func (c *Client) BuildStakeOperation( | ||
ctx context.Context, | ||
address *Address, | ||
assetID string, | ||
amount *big.Float, | ||
o ...StakingOperationOption, | ||
) (*StakingOperation, error) { | ||
return c.BuildStakingOperation(ctx, address, assetID, "stake", amount, o...) | ||
} | ||
|
||
// BuildStakeOperation will build an ephemeral staking operation using the | ||
// unstake action | ||
func (c *Client) BuildUnstakeOperation( | ||
ctx context.Context, | ||
address *Address, | ||
assetID string, | ||
amount *big.Float, | ||
o ...StakingOperationOption, | ||
) (*StakingOperation, error) { | ||
return c.BuildStakingOperation(ctx, address, assetID, "unstake", amount, o...) | ||
} | ||
|
||
// BuildStakeOperation will build an ephemeral staking operation using the | ||
// claim_stake action | ||
func (c *Client) BuildClaimStakeOperation( | ||
ctx context.Context, | ||
address *Address, | ||
assetID string, | ||
amount *big.Float, | ||
o ...StakingOperationOption, | ||
) (*StakingOperation, error) { | ||
return c.BuildStakingOperation(ctx, address, assetID, "claim_stake", amount, o...) | ||
} | ||
|
||
// FetchExternalStakingOperation loads a staking operation from the API associated | ||
// with an address. | ||
func (c *Client) FetchExternalStakingOperation(ctx context.Context, address *Address, id string) (*StakingOperation, error) { | ||
op, _, err := c.client.StakeAPI.GetExternalStakingOperation(ctx, address.NetworkID(), address.ID(), id).Execute() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return newStakingOpertionFromModel(op), nil | ||
} | ||
|
||
// StakingOperation represents a staking operation for | ||
// a given action, asset, and amount. | ||
type StakingOperation struct { | ||
model *client.StakingOperation | ||
transactions []*Transaction | ||
} | ||
|
||
// ID returns the StakingOperation ID | ||
func (o *StakingOperation) ID() string { | ||
return o.model.Id | ||
} | ||
|
||
// NetworkID returns the StakingOperation network id | ||
func (o *StakingOperation) NetworkID() string { | ||
return o.model.NetworkId | ||
} | ||
|
||
// AddressID returns the StakingOperation address id | ||
func (o *StakingOperation) AddressID() string { | ||
return o.model.AddressId | ||
} | ||
|
||
// Status returns the StakingOperation status | ||
func (o *StakingOperation) Status() string { | ||
return o.model.Status | ||
} | ||
|
||
// Transactions returns the transactions associated with | ||
// the StakingOperation | ||
func (o *StakingOperation) Transaction() []*Transaction { | ||
return o.transactions | ||
} | ||
|
||
// Sign will sign each transaction using the supplied key | ||
func (o *StakingOperation) Sign(k *ecdsa.PrivateKey) error { | ||
for _, tx := range o.Transactions() { | ||
if !tx.IsSigned() { | ||
tx.Sign(k) | ||
} | ||
} | ||
} | ||
|
||
func newStakingOperationFromModel(m *client.StakingOperation) *StakingOperation { | ||
if m == nil { | ||
return nil | ||
} | ||
|
||
transactions := make([]*Transaction, len(m.Transactions)) | ||
for i, tx := range m.Transactions { | ||
transactions[i] = newTransactionFromModel(&tx) | ||
} | ||
return &StakingOperation{ | ||
model: m, | ||
transactions: transactions, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package coinbase | ||
|
||
import "github.com/coinbase/coinbase-sdk-go/gen/client" | ||
|
||
// Transaction represents an onchain transaction | ||
type Transaction struct { | ||
model *client.Transaction | ||
} | ||
|
||
// UnsignedPayload returns the unsigned payload of the transaction | ||
func (t *Transaction) UnsignedPayload() string { | ||
return t.model.UnsignedPayload | ||
} | ||
|
||
// SignedPayload returns the signed payload of the transaction | ||
func (t *Transaction) SignedPayload() string { | ||
if t.model.SignedPayload == nil { | ||
return "" | ||
} | ||
|
||
return *t.model.SignedPayload | ||
} | ||
|
||
// TransactionHash returns the hash of the transaction | ||
func (t *Transaction) TransactionHash() string { | ||
if t.model.TransactionHash == nil { | ||
return "" | ||
} | ||
|
||
return *t.model.TransactionHash | ||
} | ||
|
||
// Status returns the status of the Transaction | ||
func (t *Transaction) Status() string { | ||
return t.model.Status | ||
} | ||
|
||
// FromAddressID returns the from address for the transaction | ||
func (t *Transaction) FromAddressID() string { | ||
return t.model.FromAddressId | ||
} | ||
|
||
func newTransactionFromModel(m *client.Transaction) *Transaction { | ||
if m == nil { | ||
return nil | ||
} | ||
return &Transaction{ | ||
model: m, | ||
} | ||
} |