diff --git a/README.md b/README.md
index 7a01f86..8fd4598 100644
--- a/README.md
+++ b/README.md
@@ -36,13 +36,7 @@ import { StakingClient } from "@coinbase/staking-client-library-ts";
const client = new StakingClient();
-client.Ethereum.stake(
- 'holesky',
- true,
- '0xdb816889F2a7362EF242E5a717dfD5B38Ae849FE', // replace with your wallet address
- '0xA55416de5DE61A0AC1aa8970a280E04388B1dE4b',
- '123',
-)
+client.Ethereum.stake('holesky', '0xdb816889F2a7362EF242E5a717dfD5B38Ae849FE', '123')
.then((workflow) => {
console.log('Workflow created %s', workflow.name);
})
@@ -57,7 +51,40 @@ client.Ethereum.stake(
Output
```text
- Workflow created: projects/62376b2f-3f24-42c9-9025-d576a3c06d6f/workflows/ffbf9b45-c57b-49cb-a4d5-fdab66d8cb25
+ Workflow created workflows/c34df125-a989-438d-8451-bd403423986a
+ ```
+
+
+
+### Stake SOL :diamond_shape_with_a_dot_inside:
+
+This code sample creates a SOL staking workflow. View the full code sample [here](examples/solana/create-workflow.ts)
+
+
+ Code Sample
+
+```typescript
+// examples/solana/create-workflow.ts
+import { StakingClient } from "@coinbase/staking-client-library-ts";
+
+const client = new StakingClient();
+
+client.Solana.stake('devnet', '8rMGARtkJY5QygP1mgvBFLsE9JrvXByARJiyNfcSE5Z', '100000000')
+ .then((workflow) => {
+ console.log('Workflow created %s', workflow.name);
+ })
+ .catch(() => {
+ throw new Error(`Error creating workflow`);
+ });
+```
+
+
+
+
+ Output
+
+ ```text
+ Workflow created workflows/e6373b20-edf0-4cf9-91ea-709328d0d63e
```
@@ -153,6 +180,28 @@ client.Ethereum.listRewards(filter).then((resp) => {
+## Build
+
+Here are some helpful commands to build and lint the project:
+
+### Generate client code
+
+```shell
+npm run gen
+```
+
+### Lint
+
+```shell
+npm run lint
+```
+
+### Lint Fix
+
+```shell
+npm run lint-fix
+```
+
## 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.cdp.coinbase.com/) for detailed definitions, API specifications, integration guides, and more!
diff --git a/docs/openapi/orchestration.swagger.json b/docs/openapi/orchestration.swagger.json
index d5ce955..3a0deb1 100644
--- a/docs/openapi/orchestration.swagger.json
+++ b/docs/openapi/orchestration.swagger.json
@@ -481,23 +481,7 @@
"in": "body",
"required": true,
"schema": {
- "type": "object",
- "properties": {
- "step": {
- "type": "integer",
- "format": "int32",
- "description": "The index of the step to be performed."
- },
- "data": {
- "type": "string",
- "description": "Transaction metadata. This is either the signed transaction or transaction hash depending on the workflow's broadcast method."
- }
- },
- "description": "The request message for PerformWorkflowStep.",
- "required": [
- "step",
- "data"
- ]
+ "$ref": "#/definitions/StakingServicePerformWorkflowStepBody"
}
}
],
@@ -745,6 +729,25 @@
"default": "BALANCE_STATE_UNSPECIFIED",
"description": "Represents the different states a stake account balance can have.\nUsed to check to see if stake is actively earning rewards or ready to be withdrawn.\n\n - BALANCE_STATE_UNSPECIFIED: The balance is not known.\n - BALANCE_STATE_INACTIVE: The balance is not actively staking.\n - BALANCE_STATE_ACTIVATING: The balance is in a warm up period and will activate in the next epoch.\n - BALANCE_STATE_ACTIVE: The balance is actively staking and earning rewards.\n - BALANCE_STATE_DEACTIVATING: The balance is in a cool down period and will be deactivated in the next epoch."
},
+ "StakingServicePerformWorkflowStepBody": {
+ "type": "object",
+ "properties": {
+ "step": {
+ "type": "integer",
+ "format": "int32",
+ "description": "The index of the step to be performed."
+ },
+ "data": {
+ "type": "string",
+ "description": "Transaction metadata. This is either the signed transaction or transaction hash depending on the workflow's broadcast method."
+ }
+ },
+ "description": "The request message for PerformWorkflowStep.",
+ "required": [
+ "step",
+ "data"
+ ]
+ },
"WaitStepOutputWaitUnit": {
"type": "string",
"enum": [
@@ -809,6 +812,36 @@
},
"description": "The amount of a token you wish to perform an action\nwith."
},
+ "v1BulkTxStepOutput": {
+ "type": "object",
+ "properties": {
+ "unsignedTxs": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "The unsigned transactions that must be signed and broadcasted.",
+ "readOnly": true
+ },
+ "state": {
+ "$ref": "#/definitions/v1BulkTxStepOutputState",
+ "description": "The state of the bulk tx step.",
+ "readOnly": true
+ }
+ },
+ "description": "The details of multiple transactions being constructed and broadcasted to the network."
+ },
+ "v1BulkTxStepOutputState": {
+ "type": "string",
+ "enum": [
+ "STATE_UNSPECIFIED",
+ "STATE_IN_PROGRESS",
+ "STATE_FAILED",
+ "STATE_COMPLETED"
+ ],
+ "default": "STATE_UNSPECIFIED",
+ "description": "State defines an enumeration of states for a staking transaction.\n\n - STATE_UNSPECIFIED: Unspecified transaction state.\n - STATE_IN_PROGRESS: Txs construction in progress.\n - STATE_FAILED: Tx construction failed.\n - STATE_COMPLETED: Tx construction completed."
+ },
"v1Contract": {
"type": "object",
"properties": {
@@ -1524,6 +1557,11 @@
"$ref": "#/definitions/v1ProvisionInfraStepOutput",
"description": "The details for provisioned infrastructure.",
"readOnly": true
+ },
+ "bulkTxStepOutput": {
+ "$ref": "#/definitions/v1BulkTxStepOutput",
+ "description": "The bulk tx step output (e.g. transaction metadata such as unsigned tx, signed tx etc).",
+ "readOnly": true
}
},
"description": "The information for a step in the workflow.",
diff --git a/docs/openapi/rewards.swagger.json b/docs/openapi/rewards.swagger.json
index dfd3207..c23e879 100644
--- a/docs/openapi/rewards.swagger.json
+++ b/docs/openapi/rewards.swagger.json
@@ -409,7 +409,7 @@
},
"date": {
"type": "string",
- "title": "The date of the reward in format 'YYYY-MM-DD' in UTC.",
+ "description": "The date of the reward in format 'YYYY-MM-DD' in UTC.",
"readOnly": true
},
"aggregationUnit": {
@@ -454,7 +454,7 @@
"readOnly": true
}
},
- "title": "Rewards earned within a particular period of time."
+ "description": "Rewards earned within a particular period of time."
},
"v1RewardRate": {
"type": "object",
@@ -537,7 +537,7 @@
"readOnly": true
}
},
- "title": "The representation of a staking activity at a particular point in time."
+ "description": "The representation of a staking activity at a particular point in time."
},
"v1USDValue": {
"type": "object",
diff --git a/examples/ethereum/create-and-process-workflow.ts b/examples/ethereum/create-and-process-workflow.ts
index 346f7ef..e58fe4e 100644
--- a/examples/ethereum/create-and-process-workflow.ts
+++ b/examples/ethereum/create-and-process-workflow.ts
@@ -11,7 +11,6 @@ import { calculateTimeDifference } from '../../src/utils/date';
const privateKey: string = ''; // replace with your private key
const stakerAddress: string = '0xdb816889F2a7362EF242E5a717dfD5B38Ae849FE'; // replace with your staker address
-const integrationAddress: string = '0xA55416de5DE61A0AC1aa8970a280E04388B1dE4b'; // replace with your integration address
const amount: string = '123'; // replace with your amount
const network: string = 'holesky'; // replace with your network
@@ -33,12 +32,7 @@ async function stakePartialEth(): Promise {
try {
// Create a new eth kiln stake workflow
- workflow = await client.Ethereum.stake(
- network,
- stakerAddress,
- integrationAddress,
- amount,
- );
+ workflow = await client.Ethereum.stake(network, stakerAddress, amount);
workflowId = workflow.name?.split('/').pop() || '';
if (workflowId == null || workflowId === '') {
diff --git a/examples/ethereum/create-workflow.ts b/examples/ethereum/create-workflow.ts
index a8adf7f..ef80354 100644
--- a/examples/ethereum/create-workflow.ts
+++ b/examples/ethereum/create-workflow.ts
@@ -2,7 +2,6 @@ import { StakingClient } from '../../src/client/staking-client';
import { Workflow } from '../../src/gen/coinbase/staking/orchestration/v1/workflow.pb';
const stakerAddress: string = '0xdb816889F2a7362EF242E5a717dfD5B38Ae849FE'; // replace with your staker address
-const integrationAddress: string = '0xA55416de5DE61A0AC1aa8970a280E04388B1dE4b'; // replace with your integration address
const amount: string = '123'; // replace with your amount
const network: string = 'holesky'; // replace with your network
@@ -17,14 +16,9 @@ async function stakePartialEth(): Promise {
try {
// Create a new eth kiln stake workflow
- workflow = await client.Ethereum.stake(
- network,
- stakerAddress,
- integrationAddress,
- amount,
- );
-
- console.log('Workflow created %s ...', workflow.name);
+ workflow = await client.Ethereum.stake(network, stakerAddress, amount);
+
+ console.log(JSON.stringify(workflow, null, 2));
} catch (error) {
let errorMessage = '';
diff --git a/examples/solana/create-and-process-workflow.ts b/examples/solana/create-and-process-workflow.ts
index d62a1a7..0e8e7ed 100644
--- a/examples/solana/create-and-process-workflow.ts
+++ b/examples/solana/create-and-process-workflow.ts
@@ -11,7 +11,6 @@ import { calculateTimeDifference } from '../../src/utils/date';
const privateKey: string = ''; // replace with your private key
const walletAddress: string = ''; // replace with your wallet address
-const validatorAddress: string = 'beefKGBWeSpHzYBHZXwp5So7wdQGX6mu4ZHCsH3uTar'; // replace with your validator address
const amount: string = '100000000'; // replace with your amount. For solana it should be >= 0.1 SOL
const network: string = 'mainnet'; // replace with your network
@@ -33,12 +32,7 @@ async function stakeSolana(): Promise {
try {
// Create a new solana stake workflow
- workflow = await client.Solana.stake(
- network,
- walletAddress,
- validatorAddress,
- amount,
- );
+ workflow = await client.Solana.stake(network, walletAddress, amount);
workflowId = workflow.name?.split('/').pop() || '';
if (workflowId == null || workflowId === '') {
diff --git a/examples/solana/create-workflow.ts b/examples/solana/create-workflow.ts
index 11dd9d9..2cb97bb 100644
--- a/examples/solana/create-workflow.ts
+++ b/examples/solana/create-workflow.ts
@@ -1,8 +1,7 @@
import { StakingClient } from '../../src/client/staking-client';
import { Workflow } from '../../src/gen/coinbase/staking/orchestration/v1/workflow.pb';
-const walletAddress: string = ''; // replace with your wallet address
-const validatorAddress: string = 'beefKGBWeSpHzYBHZXwp5So7wdQGX6mu4ZHCsH3uTar'; // replace with your validator address
+const walletAddress: string = '9NL2SkpcsdyZwsG8NmHGNra4i4NSyKbJTVd9fUQ7kJHR'; // replace with your wallet address
const amount: string = '100000000'; // replace with your amount. For solana it should be >= 0.1 SOL
const network: string = 'mainnet'; // replace with your network
@@ -17,14 +16,9 @@ async function stakeSolana(): Promise {
try {
// Create a new solana stake workflow
- workflow = await client.Solana.stake(
- network,
- walletAddress,
- validatorAddress,
- amount,
- );
-
- console.log('Workflow created %s ...', workflow.name);
+ workflow = await client.Solana.stake(network, walletAddress, amount);
+
+ console.log(JSON.stringify(workflow, null, 2));
} catch (error) {
let errorMessage = '';
diff --git a/scripts/generate-client.sh b/scripts/generate-client.sh
index a430fdb..9d19851 100755
--- a/scripts/generate-client.sh
+++ b/scripts/generate-client.sh
@@ -3,4 +3,4 @@
buf generate --template protos/buf.gen.orchestration.yaml buf.build/cdp/orchestration --path coinbase/staking/orchestration/v1 --include-imports --include-wkt
buf generate --template protos/buf.gen.rewards.yaml buf.build/cdp/rewards --path coinbase/staking/rewards/v1 --include-imports --include-wkt
# TODO: Remove this once the generation issue is fixed.
-find ./src/gen -type f -exec sed -I '' -e 's/parentprotocols/parent/g' -e 's/parentprotocolsnetworks/parents/g' -e 's/parentnetworks/parent/g' -e 's/nameprojectsworkflows/name/g' -e 's/parentprojects/parent/g' -e 's/nameworkflows/name/g' {} \;
+find ./src/gen -type f -exec sed -I '' -e 's/parentprotocols/parent/g' -e 's/parentprotocolsnetworks/parents/g' -e 's/parentnetworks/parent/g' -e 's/nameprojectsworkflows/name/g' -e 's/nameworkflows/name/g' {} \;
diff --git a/src/client/protocols/ethereum-kiln-staking.ts b/src/client/protocols/ethereum-kiln-staking.ts
index 756cb17..34fb17e 100644
--- a/src/client/protocols/ethereum-kiln-staking.ts
+++ b/src/client/protocols/ethereum-kiln-staking.ts
@@ -26,8 +26,8 @@ export class Ethereum {
async stake(
network: string,
stakerAddress: string,
- integratorContractAddress: string,
amount: string,
+ integratorContractAddress?: string,
): Promise {
const req: CreateWorkflowRequest = {
workflow: {
@@ -51,8 +51,8 @@ export class Ethereum {
async unstake(
network: string,
stakerAddress: string,
- integratorContractAddress: string,
amount: string,
+ integratorContractAddress?: string,
): Promise {
const req: CreateWorkflowRequest = {
workflow: {
@@ -76,7 +76,7 @@ export class Ethereum {
async claimStake(
network: string,
stakerAddress: string,
- integratorContractAddress: string,
+ integratorContractAddress?: string,
): Promise {
const req: CreateWorkflowRequest = {
workflow: {
diff --git a/src/client/protocols/solana-staking.ts b/src/client/protocols/solana-staking.ts
index 94768d0..f7e73f8 100644
--- a/src/client/protocols/solana-staking.ts
+++ b/src/client/protocols/solana-staking.ts
@@ -26,8 +26,8 @@ export class Solana {
async stake(
network: string,
walletAddress: string,
- validatorAddress: string,
amount: string,
+ validatorAddress?: string,
): Promise {
const req: CreateWorkflowRequest = {
workflow: {
diff --git a/src/client/staking-client.ts b/src/client/staking-client.ts
index 6435cba..eb5f53c 100644
--- a/src/client/staking-client.ts
+++ b/src/client/staking-client.ts
@@ -130,7 +130,7 @@ export class StakingClient {
return StakingService.ViewStakingContext(req, initReq);
}
- // Create a workflow under a given project. This function takes the entire req object as input.
+ // Create a workflow. This function takes the entire req object as input.
// Use the protocol-specific helper functions like Ethereum.Stake to create a protocol and action specific workflow.
async createWorkflow(req: CreateWorkflowRequest): Promise {
const path: string = `/v1/workflows`;
@@ -143,7 +143,7 @@ export class StakingClient {
return StakingService.CreateWorkflow(req, initReq);
}
- // Get a workflow given its project and workflow id.
+ // Get a workflow given workflow id.
async getWorkflow(workflowId: string): Promise {
const name: string = `workflows/${workflowId}`;
const path: string = `/v1/${name}`;
@@ -183,7 +183,7 @@ export class StakingClient {
return StakingService.PerformWorkflowStep(req, initReq);
}
- // List workflows for a given project.
+ // List your workflows.
async listWorkflows(
pageSize: number = 100,
filter: string = '',
diff --git a/src/gen/coinbase/staking/orchestration/v1/workflow.pb.ts b/src/gen/coinbase/staking/orchestration/v1/workflow.pb.ts
index 899e1e7..d0c36f1 100644
--- a/src/gen/coinbase/staking/orchestration/v1/workflow.pb.ts
+++ b/src/gen/coinbase/staking/orchestration/v1/workflow.pb.ts
@@ -54,6 +54,13 @@ export enum ProvisionInfraStepOutputState {
STATE_FAILED = "STATE_FAILED",
}
+export enum BulkTxStepOutputState {
+ STATE_UNSPECIFIED = "STATE_UNSPECIFIED",
+ STATE_IN_PROGRESS = "STATE_IN_PROGRESS",
+ STATE_FAILED = "STATE_FAILED",
+ STATE_COMPLETED = "STATE_COMPLETED",
+}
+
export enum WorkflowState {
STATE_UNSPECIFIED = "STATE_UNSPECIFIED",
STATE_IN_PROGRESS = "STATE_IN_PROGRESS",
@@ -82,13 +89,18 @@ export type ProvisionInfraStepOutput = {
state?: ProvisionInfraStepOutputState
}
+export type BulkTxStepOutput = {
+ unsignedTxs?: string[]
+ state?: BulkTxStepOutputState
+}
+
type BaseWorkflowStep = {
name?: string
}
export type WorkflowStep = BaseWorkflowStep
- & OneOf<{ txStepOutput: TxStepOutput; waitStepOutput: WaitStepOutput; provisionInfraStepOutput: ProvisionInfraStepOutput }>
+ & OneOf<{ txStepOutput: TxStepOutput; waitStepOutput: WaitStepOutput; provisionInfraStepOutput: ProvisionInfraStepOutput; bulkTxStepOutput: BulkTxStepOutput }>
type BaseWorkflow = {