-
Notifications
You must be signed in to change notification settings - Fork 6
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 #14 from coinbase/main-1712589815
Release v.0.5.1
- Loading branch information
Showing
11 changed files
with
825 additions
and
154 deletions.
There are no files selected for viewing
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,14 @@ | ||
import { StakingClient } from '../../src/client/staking-client'; | ||
|
||
// Defines which address and rewards we want to see | ||
const address: string = 'cosmosvaloper1c4k24jzduc365kywrsvf5ujz4ya6mwympnc4en'; | ||
const filter: string = `address='${address}' AND period_end_time > '2024-03-25T00:00:00Z' AND period_end_time < '2024-03-27T00:00:00Z'`; | ||
|
||
const client = new StakingClient(); | ||
|
||
// Loops through rewards array and prints each reward | ||
client.Cosmos.listRewards(filter).then((resp) => { | ||
resp.rewards!.forEach((reward) => { | ||
console.log(JSON.stringify(reward, null, 2)); | ||
}); | ||
}); |
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,37 @@ | ||
import { StakingClient } from '../../src/client/staking-client'; | ||
|
||
// TODO: Replace address as per your requirement. | ||
const address: string = 'cosmosvaloper1c4k24jzduc365kywrsvf5ujz4ya6mwympnc4en'; | ||
|
||
const client = new StakingClient(); | ||
|
||
async function listStakes(): Promise<void> { | ||
if (address === '') { | ||
throw new Error('Please set the address variable in this file'); | ||
} | ||
|
||
const filter: string = `address='${address}'`; | ||
|
||
try { | ||
// List cosmos staking balances | ||
let resp = await client.Cosmos.listStakes(filter); | ||
|
||
let count = 0; | ||
|
||
// Loop through staked balance array and print each balance | ||
resp.stakes!.forEach((stake) => { | ||
count++; | ||
const marshaledStake = JSON.stringify(stake); | ||
|
||
console.log(`[${count}] Stake details: ${marshaledStake}`); | ||
}); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
throw new Error(`Error listing staking balances: ${error.message}`); | ||
} | ||
} | ||
} | ||
|
||
listStakes().catch((error) => { | ||
console.error('Error listing cosmos staking balances: ', error.message); | ||
}); |
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,188 @@ | ||
import { TxSignerFactory } from '../../src/signers'; | ||
import { | ||
StakingClient, | ||
workflowHasFinished, | ||
workflowWaitingForSigning, | ||
workflowWaitingForExternalBroadcast, | ||
isTxStepOutput, | ||
isWaitStepOutput, | ||
} from '../../src/client/staking-client'; | ||
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 | ||
const amount: string = '100000000'; // replace with your amount. For solana it should be >= 0.1 SOL | ||
const network: string = 'mainnet'; // replace with your network | ||
|
||
const client = new StakingClient(); | ||
|
||
const signer = TxSignerFactory.getSigner('solana'); | ||
|
||
async function stakeSolana(): Promise<void> { | ||
if (projectId === '' || walletAddress === '') { | ||
throw new Error( | ||
'Please set the projectId and stakerAddress variables in this file', | ||
); | ||
} | ||
|
||
let unsignedTx = ''; | ||
let workflow: Workflow = {} as Workflow; | ||
let currentStepId: number | undefined; | ||
let workflowId: string; | ||
|
||
try { | ||
// Create a new solana stake workflow | ||
workflow = await client.Solana.stake( | ||
projectId, | ||
network, | ||
true, | ||
walletAddress, | ||
validatorAddress, | ||
amount, | ||
); | ||
|
||
workflowId = workflow.name?.split('/').pop() || ''; | ||
if (workflowId == null || workflowId === '') { | ||
throw new Error('Unexpected workflow state. workflowId is null'); | ||
} | ||
|
||
currentStepId = workflow.currentStepId; | ||
if (currentStepId == null) { | ||
throw new Error('Unexpected workflow state. currentStepId is null'); | ||
} | ||
|
||
console.log('Workflow created %s ...', workflow.name); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
throw new Error(`Error creating workflow: ${error.message}`); | ||
} | ||
|
||
const msg = JSON.stringify(error); | ||
|
||
throw new Error(`Error creating workflow ${msg}`); | ||
} | ||
|
||
// Loop until the workflow has reached an end state. | ||
// eslint-disable-next-line no-constant-condition | ||
while (true) { | ||
// Every second, get the latest workflow state. | ||
// If the workflow is waiting for signing, sign the unsigned tx and return back the signed tx. | ||
// 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); | ||
} catch (error) { | ||
// TODO: add retry logic for network errors | ||
if (error instanceof Error) { | ||
throw new Error(`Error getting workflow: ${error.message}`); | ||
} | ||
} | ||
|
||
await printWorkflowProgressDetails(workflow); | ||
|
||
if (workflowWaitingForSigning(workflow)) { | ||
unsignedTx = | ||
workflow.steps![currentStepId].txStepOutput?.unsignedTx || ''; | ||
if (unsignedTx === '') { | ||
console.log('Waiting for unsigned tx to be available ...'); | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); // sleep for 1 second | ||
continue; | ||
} | ||
|
||
console.log('Signing unsigned tx %s ...', unsignedTx); | ||
const signedTx = await signer.signTransaction(privateKey, unsignedTx); | ||
|
||
console.log('Returning back signed tx %s ...', signedTx); | ||
|
||
workflow = await client.performWorkflowStep( | ||
projectId, | ||
workflowId, | ||
currentStepId, | ||
signedTx, | ||
); | ||
} else if (workflowWaitingForExternalBroadcast(workflow)) { | ||
unsignedTx = | ||
workflow.steps![currentStepId].txStepOutput?.unsignedTx || ''; | ||
if (unsignedTx === '') { | ||
console.log('Waiting for unsigned tx to be available ...'); | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); // sleep for 1 second | ||
continue; | ||
} | ||
|
||
console.log('Signing unsigned tx %s ...', unsignedTx); | ||
|
||
const signedTx = await signer.signTransaction(privateKey, unsignedTx); | ||
|
||
console.log( | ||
'Please broadcast this signed tx %s externally and return back the tx hash via the PerformWorkflowStep API ...', | ||
signedTx, | ||
); | ||
break; | ||
} else if (workflowHasFinished(workflow)) { | ||
console.log('Workflow completed with state %s ...', workflow.state); | ||
break; | ||
} | ||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000)); // sleep for 1 second | ||
} | ||
} | ||
|
||
async function printWorkflowProgressDetails(workflow: Workflow): Promise<void> { | ||
if (workflow.steps == null || workflow.steps.length === 0) { | ||
console.log('Waiting for steps to be created ...'); | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); // sleep for 1 second | ||
return; | ||
} | ||
|
||
const currentStepId = workflow.currentStepId; | ||
|
||
if (currentStepId == null) { | ||
return; | ||
} | ||
|
||
const step = workflow.steps[currentStepId]; | ||
|
||
let stepDetails = ''; | ||
|
||
if (isTxStepOutput(step)) { | ||
stepDetails = `state: ${step.txStepOutput?.state} tx hash: ${step.txStepOutput?.txHash}`; | ||
} else if (isWaitStepOutput(step)) { | ||
stepDetails = `state: ${step.waitStepOutput?.state}} current: ${step.waitStepOutput?.current}} target: ${step.waitStepOutput?.target}`; | ||
} else { | ||
throw new Error('Encountered unexpected workflow step type'); | ||
} | ||
|
||
const runtime = calculateTimeDifference( | ||
<string>workflow.createTime, | ||
<string>workflow.updateTime, | ||
); | ||
|
||
if (workflowHasFinished(workflow)) { | ||
console.log( | ||
'Workflow reached end state - step name: %s %s workflow state: %s runtime: %d seconds', | ||
step.name, | ||
stepDetails, | ||
workflow.state, | ||
runtime, | ||
); | ||
} else { | ||
console.log( | ||
'Waiting for workflow to finish - step name: %s %s workflow state: %s runtime: %d seconds', | ||
step.name, | ||
stepDetails, | ||
workflow.state, | ||
runtime, | ||
); | ||
} | ||
} | ||
|
||
stakeSolana() | ||
.then(() => { | ||
console.log('Done staking sol'); | ||
}) | ||
.catch((error) => { | ||
console.error('Error staking sol: ', error.message); | ||
}); |
Oops, something went wrong.