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

Release v.0.5.1 #14

Merged
merged 2 commits into from
Apr 8, 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
14 changes: 14 additions & 0 deletions examples/cosmos/list-rewards.ts
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));
});
});
37 changes: 37 additions & 0 deletions examples/cosmos/list-stakes.ts
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);
});
4 changes: 2 additions & 2 deletions examples/ethereum/list-stakes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async function listStakes(): Promise<void> {

let count = 0;

// Loop through rewards array and print each reward
// Loop through staked balance array and print each balance
resp.stakes!.forEach((stake) => {
count++;
const marshaledStake = JSON.stringify(stake);
Expand All @@ -34,5 +34,5 @@ async function listStakes(): Promise<void> {
}

listStakes().catch((error) => {
console.error('Error listing solana staking balances: ', error.message);
console.error('Error listing ethereum staking balances: ', error.message);
});
188 changes: 188 additions & 0 deletions examples/solana/create-and-process-workflow.ts
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);
});
Loading
Loading