Skip to main content

Workflows

The Orchestration API simplifies the management of staking transactions across various protocols with the help of its core feature: the workflow. A workflow represents a comprehensive backend process designed to manage all tasks required to complete any given staking action end-to-end.

This system is protocol-agnostic, meaning it can adapt to the specific needs of different protocols without requiring a need to introduce new interfaces every time we want to add a new protocol.

What does a workflow look like

Here's an example of a workflow created in order to stake partial eth (amounts less than 32 eth) using the Kiln integration:

What's a workflow

How do we start a workflow

Every staking action is represented by a Workflow. To start a workflow, you need to only provide the following information:

  1. Action name: The action you want to perform, and the protocol, network you want to do it on. Ex: protocols/ethereum_kiln/networks/holesky/actions/stake represents the action of "staking" "eth" on the "holesky" network.

  2. Staking parameters: The parameters required to perform the action. Ex: For partial eth staking, you need to provide the wallet address you want to stake from, and the amount of eth you want to stake. The details of the parameters required for each action are provided in the protocol specific guides.

Good news - we have 2 clients (Typescript & Go) which make the process of starting a workflow even simpler. Here's an example of what that looks like:

import { StakingClient } from '@coinbase/staking-client-library-ts';

const client = new StakingClient();

// The ts client abstracts away the concept of workflows and exposes helper functions
// to expose intents such as stake, unstake etc.
client.Ethereum.stake(network, stakerAddress, amount);

How to interact with a workflow

A workflow is designed to consume the staking intent once and from there on independently manage the entire lifecycle of the staking transaction. The only time the workflow needs intervention is when it needs customer input, which typically is when we want a customer to sign and broadcast our unsigned txs.

Here's a rough algorithm of what a typical interaction with a workflow can look like:

  1. Create a workflow by providing the action name and staking parameters.

  2. Poll and get the workflow to know what the current workflow state is.

    1. When the workflow state changes to WAITING_FOR_EXT_BROADCAST, you can read and consume the unsigned tx from the step currently being executed.

    2. If the unsigned tx is as per your needs, you can at this point sign and broadcast it.

    3. The workflow has ways of inferencing whether our unsigned tx was indeed signed and broadcasted. If it was, the workflow will mark the current step has completed and move to the next step.

  3. When there are no more steps left to execute, the workflow will move to the completed state.

Here's an example of a hypothetical workflow comprising 3 steps that are executed serially. The only time the workflow pauses is when it needs the customer to sign and broadcast the unsigned tx from step 1 - rest of the steps are executed independently by the workflow itself.

Workflow Lifecycle
info

The Orchestration API as of today, expects the customer to sign and broadcast the unsigned txs generated by the API. If you are a developer, who is interested in broadcasting tx capabilities and would like to use an API developed by us then do reach out to us on our staking discord channel.

Workflow States

The workflow state is a high-level state that describes the current state of the workflow. The workflow state is different from the individual step state, which describes the state of the step that the workflow is currently executing.

StateDefinitionTerminal State
STATE_IN_PROGRESSThe workflow is making progress and currently does not need any inputsFalse
STATE_WAITING_FOR_EXT_BROADCASTThe workflow is waiting for our generated unsigned tx to be signed and broadcastedFalse
STATE_COMPLETEDThe workflow has successfully completedTrue
STATE_FAILEDThe workflow has failed at a step - check step details for errorTrue

Workflow Steps

Workflows consist of steps, each representing a distinct task that the API automates to facilitate the staking action. These steps can be of different types representing the various tasks that need to be done to complete a staking action. Here are some examples of the types of steps that can be found in a workflow:

Customer input needed: YES

This is the most commonly used step type and is responsible for constructing a non-custodial transactions in the required format. Users need to sign and broadcast this transaction, after which the API monitors to make sure it has landed onchain.

Here's what it looks like within a workflow:

{
"name": "stake tx",
"txStepOutput": {
"unsignedTx": "02f3824268068502540be40085041dad875c83061a8094a55416de5de61a0ac1aa8970a280e04388b1de4b7b843a4b66f1c0808080",
"txHash": "",
"state": "STATE_PENDING_EXT_BROADCAST",
"errorMessage": ""
}
}

The table below details the full list of tx step states that are available and what they mean:

StateDefinitionTerminal State
STATE_NOT_CONSTRUCTEDThe unsigned transaction is being constructedFalse
STATE_CONSTRUCTEDThe unsigned transaction has been constructed, but not yet available for useFalse
STATE_PENDING_EXT_BROADCASTThe generated unsigned tx is waiting to be signed and broadcastedFalse
STATE_CONFIRMINGThe transaction is waiting to be included in a blockFalse
STATE_CONFIRMEDThe transaction has been confirmed in a block, but is awaiting additional confirmations to be finalizedFalse
STATE_FINALIZEDThe transaction has the correct number of confirmations and is now considered finalized onchainTrue
STATE_FAILEDThe transaction has failed for one or many reasons, with the specific error provided in the step payloadTrue
End-to-End Staking Example
info

While this example deals with an individual person wanting to stake, the Staking API is designed in a way for developers to build staking into their applications.

Now that we have explored what Workflows are, how to start them and how to go about gating staking actions, we can look into a complete end-to-end staking example.

Case Study: User "Alice" loves Ethereum and would like to do her part of making the network stronger by staking some ETH. Staking makes the network happy and also give her some rewards in return. But she realizes that as of today (May 2023) Ethereum only allows multiples of 32 ETH to be staked. She unfortunately has only 15 ETH in her wallet but would like to be able to stake some part of that. But there's good news - she finds that Coinbase in partnership with Kiln have launched the Partial ETH Staking solution that allows her to stake any amount of ETH even lesser than 32 ETH. She's excited and wants to get started. She finds that Coinbase has a Staking API precisely for this that she would like to leverage. She loves Typescript and finds that Coinbase supports a staking client for it.

Step 1: Set up the Staking Client

import { StakingClient } from '@coinbase/staking-client-library-ts';

const client = new StakingClient();

Step 2: Fetch Staking Context

Alice first needs to fetch her staking context to see if she has enough ETH to stake. Although in this case, she already knows she has 15 ETH, but while trying to programmatically implement an e2e staking action, it's always nice to have pre-checks and make sure all is good. For example, if she was trying to unstake her ETH, she wouldn't know exactly how much her ETH has grown and would need some API to tell her, her current total staked balance.

stakingContext = await client.Ethereum.viewStakingContext('alice-wallet-address', 'holesky');

She finds that she has 15 ETH in her wallet and is willing to stake 10 ETH from it.

Step 3: Start a "Stake" Workflow

Alice starts a workflow to stake 10 ETH.

workflow = await client.Ethereum.stake('holesky', 'alice-wallet-address', '10000000000000000000');

Step 3: Poll Workflow until workflow state is WAITING_FOR_EXT_BROADCAST or COMPLETED

while (true) {
workflow = await client.getWorkflow(workflowId);

if (workflowWaitingForExternalBroadcast(workflow)) {
unsignedTx = workflow.steps![workflow.currentStepId!].txStepOutput?.unsignedTx || '';
console.log('Please sign and broadcast this unsigned tx %s ...', unsignedTx);
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
}

Step 4: Sign and Broadcast the unsigned tx

Alice signs and broadcasts the unsigned tx corresponding to the intent "stake 10 ETH" provided by the workflow.

Step 5: Workflow reaches "COMPLETED" state

Workflow marks the 1st tx step state as FINALIZED after it finds that Alice's broadcasted tx has landed on chain and is greater than a safe finalization depth.

Since there are no more steps to execute, the workflow reaches the "COMPLETED" state and the end result is that Alice's 10 ETH is successfully staked.

At this point, Alice can sit back, relax and watch her staked ETH grow and also earn rewards in the process.

Was this helpful?