diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..2691df0 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,24 @@ +name: TypeScript Lint + +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + lint: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "20.x" + registry-url: "https://registry.npmjs.org" + - run: npm ci + - name: Run linter + run: npm run lint diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d201051..bce32b1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,11 +15,11 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: '18.x' - registry-url: 'https://registry.npmjs.org' + node-version: "20.x" + registry-url: "https://registry.npmjs.org" - run: npm install -g npm@^9.5.0 - run: npm ci - run: npm publish --provenance --access public diff --git a/.gitignore b/.gitignore index 737fe95..a13a9e2 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ staking-client-* dist/ node_modules/ + +# VSCode configuration +.vscode diff --git a/README.md b/README.md index 250c122..a41f3b5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A traditional infrastructure-heavy staking integration can take months. Coinbase ## Quick Start -Prerequisite: [Node 18.12+](https://nodejs.org/en/blog/release/v18.12.0) +Prerequisite: [Node 20+](https://www.npmjs.com/package/node/v/20.11.1) 1. Install this package: `npm install @coinbase/staking-client-library-ts` 2. Create and download an API key from the [Cloud Platform](https://portal.cloud.coinbase.com/access/api). @@ -37,10 +37,9 @@ import { StakingClient } from "@coinbase/staking-client-library-ts"; const client = new StakingClient(); client.Ethereum.stake( - 'your-project-id', // replace with your project id 'holesky', true, - 'your-wallet-address', // replace with your wallet address + '0xdb816889F2a7362EF242E5a717dfD5B38Ae849FE', // replace with your wallet address '0xA55416de5DE61A0AC1aa8970a280E04388B1dE4b', '123', ) diff --git a/examples/ethereum/create-and-process-workflow.ts b/examples/ethereum/create-and-process-workflow.ts index f81ad87..346f7ef 100644 --- a/examples/ethereum/create-and-process-workflow.ts +++ b/examples/ethereum/create-and-process-workflow.ts @@ -9,9 +9,8 @@ import { import { Workflow } from '../../src/gen/coinbase/staking/orchestration/v1/workflow.pb'; import { calculateTimeDifference } from '../../src/utils/date'; -const projectId: string = ''; // replace with your project id const privateKey: string = ''; // replace with your private key -const stakerAddress: string = ''; // replace with your staker address +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 @@ -21,9 +20,9 @@ const client = new StakingClient(); const signer = TxSignerFactory.getSigner('ethereum'); async function stakePartialEth(): Promise { - if (projectId === '' || privateKey === '' || stakerAddress === '') { + if (privateKey === '' || stakerAddress === '') { throw new Error( - 'Please set the projectId, privateKey and stakerAddress variables in this file', + 'Please set the privateKey and stakerAddress variables in this file', ); } @@ -35,7 +34,6 @@ async function stakePartialEth(): Promise { try { // Create a new eth kiln stake workflow workflow = await client.Ethereum.stake( - projectId, network, stakerAddress, integrationAddress, @@ -68,7 +66,7 @@ async function stakePartialEth(): Promise { // If the workflow is waiting for external broadcast, sign and broadcast the unsigned tx externally and return back the tx hash via the PerformWorkflowStep API. // Note: In this example, we just log this message as the wallet provider needs to implement this logic. try { - workflow = await client.getWorkflow(projectId, workflowId); + workflow = await client.getWorkflow(workflowId); } catch (error) { // TODO: add retry logic for network errors if (error instanceof Error) { diff --git a/examples/ethereum/create-workflow.ts b/examples/ethereum/create-workflow.ts index 60704f3..a8adf7f 100644 --- a/examples/ethereum/create-workflow.ts +++ b/examples/ethereum/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 projectId: string = ''; // replace with your project id -const stakerAddress: string = ''; // replace with your staker address +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 @@ -10,10 +9,8 @@ const network: string = 'holesky'; // replace with your network const client = new StakingClient(); async function stakePartialEth(): Promise { - if (projectId === '' || stakerAddress === '') { - throw new Error( - 'Please set the projectId and stakerAddress variables in this file', - ); + if (stakerAddress === '') { + throw new Error('Please set the stakerAddress variable in this file'); } let workflow: Workflow = {} as Workflow; @@ -21,7 +18,6 @@ async function stakePartialEth(): Promise { try { // Create a new eth kiln stake workflow workflow = await client.Ethereum.stake( - projectId, network, stakerAddress, integrationAddress, diff --git a/examples/solana/create-and-process-workflow.ts b/examples/solana/create-and-process-workflow.ts index a88dba4..d62a1a7 100644 --- a/examples/solana/create-and-process-workflow.ts +++ b/examples/solana/create-and-process-workflow.ts @@ -9,7 +9,6 @@ import { import { Workflow } from '../../src/gen/coinbase/staking/orchestration/v1/workflow.pb'; import { calculateTimeDifference } from '../../src/utils/date'; -const projectId: string = ''; // replace with your project id 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 @@ -21,9 +20,9 @@ const client = new StakingClient(); const signer = TxSignerFactory.getSigner('solana'); async function stakeSolana(): Promise { - if (projectId === '' || walletAddress === '') { + if (privateKey === '' || walletAddress === '') { throw new Error( - 'Please set the projectId and stakerAddress variables in this file', + 'Please set the privateKey and walletAddress variables in this file', ); } @@ -35,7 +34,6 @@ async function stakeSolana(): Promise { try { // Create a new solana stake workflow workflow = await client.Solana.stake( - projectId, network, walletAddress, validatorAddress, @@ -71,7 +69,7 @@ async function stakeSolana(): Promise { // If the workflow is waiting for external broadcast, sign and broadcast the unsigned tx externally and return back the tx hash via the PerformWorkflowStep API. // Note: In this example, we just log this message as the wallet provider needs to implement this logic. try { - workflow = await client.getWorkflow(projectId, workflowId); + workflow = await client.getWorkflow(workflowId); } catch (error) { // TODO: add retry logic for network errors if (error instanceof Error) { diff --git a/examples/solana/create-workflow.ts b/examples/solana/create-workflow.ts index 5a4da2f..11dd9d9 100644 --- a/examples/solana/create-workflow.ts +++ b/examples/solana/create-workflow.ts @@ -1,7 +1,6 @@ import { StakingClient } from '../../src/client/staking-client'; import { Workflow } from '../../src/gen/coinbase/staking/orchestration/v1/workflow.pb'; -const projectId: string = ''; // replace with your project id 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 @@ -10,10 +9,8 @@ const network: string = 'mainnet'; // replace with your network const client = new StakingClient(); async function stakeSolana(): Promise { - if (projectId === '' || walletAddress === '') { - throw new Error( - 'Please set the projectId and stakerAddress variables in this file', - ); + if (walletAddress === '') { + throw new Error('Please set the walletAddress variable in this file'); } let workflow: Workflow = {} as Workflow; @@ -21,7 +18,6 @@ async function stakeSolana(): Promise { try { // Create a new solana stake workflow workflow = await client.Solana.stake( - projectId, network, walletAddress, validatorAddress, diff --git a/package.json b/package.json index 43be268..23b9bae 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "clean-gen": "rm -rf src/gen/* && rm -rf docs/openapi/*", "build": "npm run clean && tsc", "prepare": "npm run build", - "lint": "eslint . --ext .ts --ignore-pattern '/dist/*/*'", - "lint-fix": "eslint . --ext .ts --fix --ignore-pattern '/dist/*/*'" + "lint": "eslint . --ext .ts --ignore-pattern '/dist/*/*' --ignore-pattern '/src/gen/*/*'", + "lint-fix": "eslint . --ext .ts --fix --ignore-pattern '/dist/*/*' --ignore-pattern '/src/gen/*/*'" }, "publishConfig": { "access": "public", diff --git a/src/client/protocols/ethereum-kiln-staking.ts b/src/client/protocols/ethereum-kiln-staking.ts index 0ec9cc3..756cb17 100644 --- a/src/client/protocols/ethereum-kiln-staking.ts +++ b/src/client/protocols/ethereum-kiln-staking.ts @@ -24,7 +24,6 @@ export class Ethereum { } async stake( - projectId: string, network: string, stakerAddress: string, integratorContractAddress: string, @@ -46,11 +45,10 @@ export class Ethereum { }, }; - return this.parent.createWorkflow(projectId, req); + return this.parent.createWorkflow(req); } async unstake( - projectId: string, network: string, stakerAddress: string, integratorContractAddress: string, @@ -72,11 +70,10 @@ export class Ethereum { }, }; - return this.parent.createWorkflow(projectId, req); + return this.parent.createWorkflow(req); } async claimStake( - projectId: string, network: string, stakerAddress: string, integratorContractAddress: string, @@ -93,7 +90,7 @@ export class Ethereum { }, }; - return this.parent.createWorkflow(projectId, req); + return this.parent.createWorkflow(req); } async viewStakingContext( diff --git a/src/client/protocols/solana-staking.ts b/src/client/protocols/solana-staking.ts index 69cc201..94768d0 100644 --- a/src/client/protocols/solana-staking.ts +++ b/src/client/protocols/solana-staking.ts @@ -24,7 +24,6 @@ export class Solana { } async stake( - projectId: string, network: string, walletAddress: string, validatorAddress: string, @@ -46,11 +45,10 @@ export class Solana { }, }; - return this.parent.createWorkflow(projectId, req); + return this.parent.createWorkflow(req); } async unstake( - projectId: string, network: string, walletAddress: string, stakeAccountAddress: string, @@ -72,11 +70,10 @@ export class Solana { }, }; - return this.parent.createWorkflow(projectId, req); + return this.parent.createWorkflow(req); } async claimStake( - projectId: string, network: string, walletAddress: string, stakeAccountAddress: string, @@ -93,7 +90,7 @@ export class Solana { }, }; - return this.parent.createWorkflow(projectId, req); + return this.parent.createWorkflow(req); } async viewStakingContext( diff --git a/src/client/staking-client.ts b/src/client/staking-client.ts index 855850b..6435cba 100644 --- a/src/client/staking-client.ts +++ b/src/client/staking-client.ts @@ -132,12 +132,8 @@ export class StakingClient { // Create a workflow under a given project. 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( - projectId: string, - req: CreateWorkflowRequest, - ): Promise { - const parent: string = `projects/${projectId}`; - const path: string = `/v1/${parent}/workflows`; + async createWorkflow(req: CreateWorkflowRequest): Promise { + const path: string = `/v1/workflows`; const method: string = 'POST'; const url: string = this.baseURL + '/orchestration'; @@ -148,9 +144,8 @@ export class StakingClient { } // Get a workflow given its project and workflow id. - async getWorkflow(projectId: string, workflowId: string): Promise { - const parent: string = `projects/${projectId}`; - const name: string = `${parent}/workflows/${workflowId}`; + async getWorkflow(workflowId: string): Promise { + const name: string = `workflows/${workflowId}`; const path: string = `/v1/${name}`; const method: string = 'GET'; const url: string = this.baseURL + '/orchestration'; @@ -167,12 +162,10 @@ export class StakingClient { // Return back a signed tx or a broadcasted tx hash for a given workflow and step number. async performWorkflowStep( - projectId: string, workflowId: string, stepIndex: number, data: string, ): Promise { - const parent: string = `projects/${projectId}`; const name: string = `${parent}/workflows/${workflowId}`; const path: string = `/v1/${name}/step`; const method: string = 'POST'; @@ -192,12 +185,10 @@ export class StakingClient { // List workflows for a given project. async listWorkflows( - project: string, pageSize: number = 100, filter: string = '', ): Promise { - const parent: string = `projects/${project}`; - const path: string = `/v1/${parent}/workflows`; + const path: string = `/v1/workflows`; const method: string = 'GET'; const url: string = this.baseURL + '/orchestration';