Skip to content

Commit

Permalink
Add wallet model support for Dedicated ETH Staking
Browse files Browse the repository at this point in the history
  • Loading branch information
drohit-cb committed Aug 9, 2024
1 parent 1bc6462 commit 340c675
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 24 deletions.
44 changes: 23 additions & 21 deletions src/coinbase/address/wallet_address.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Decimal } from "decimal.js";
import { ethers } from "ethers";
import { Address as AddressModel, StakingOperationStatusEnum } from "../../client";
import { Address as AddressModel } from "../../client";
import { Address } from "../address";
import { Asset } from "../asset";
import { Coinbase } from "../coinbase";
Expand Down Expand Up @@ -253,7 +253,7 @@ export class WalletAddress extends Address {
/**
* Trades the given amount of the given Asset for another Asset. Only same-network Trades are supported.
*
* @param options = The options to create the Trade.
* @param options - = The options to create the Trade.
* @param options.amount - The amount of the From Asset to send.
* @param options.fromAssetId - The ID of the Asset to trade from.
* @param options.toAssetId - The ID of the Asset to trade to.
Expand Down Expand Up @@ -503,32 +503,34 @@ export class WalletAddress extends Address {
options,
);

// NOTE: Staking does not yet support server signers at this point.
await stakingOperation.sign(this.key!);
for (let i = 0; i < stakingOperation.getTransactions().length; i++) {
const transaction = stakingOperation.getTransactions()[0];
if (!transaction.isSigned()) {
continue;
const startTime = Date.now();

// Loop until the staking operation is complete.
while (!stakingOperation.isTerminalState() && Date.now() - startTime < timeoutSeconds * 1000) {
// Loop through any unsigned transactions that are available, sign and broadcast them.
for (let i = 0; i < stakingOperation.getTransactions().length; i++) {
const transaction = stakingOperation.getTransactions()[i];

if (!transaction.isSigned()) {
await transaction.sign(this.key!);

stakingOperation = await this.broadcastStakingOperationRequest(
stakingOperation,
transaction.getSignedPayload()!.slice(2),
i,
);
}
}
stakingOperation = await this.broadcastStakingOperationRequest(
stakingOperation,
transaction.getSignedPayload()!.slice(2),
i,
);
}

const startTime = Date.now();
while (Date.now() - startTime < timeoutSeconds * 1000) {
await stakingOperation.reload();
const status = stakingOperation.getStatus();
if (
status === StakingOperationStatusEnum.Complete ||
status === StakingOperationStatusEnum.Failed
) {

if (stakingOperation.isTerminalState()) {
return stakingOperation;
}

await delay(intervalSeconds);
}

throw new Error("Staking Operation timed out");
}

Expand Down
27 changes: 27 additions & 0 deletions src/coinbase/staking_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ export class StakingOperation {
return this.transactions;
}

/**
* Return a human-readable string representation of the StakingOperation object.
*
* @returns The string representation of the StakingOperation object.
*/
public toString(): string {
return JSON.stringify(this.model, null, 2);
}

/**
* Get signed voluntary exit messages for native eth unstaking
*
Expand All @@ -133,6 +142,24 @@ export class StakingOperation {
* @returns Whether the Staking operation is in a terminal State
*/
isTerminalState(): boolean {
return this.isComplete() || this.isFailed();
}

/**
* Returns whether the Staking operation is in a failed state.
*
* @returns Whether the Staking operation is in a failed state.
*/
isFailed(): boolean {
return this.getStatus() === StakingOperationStatusEnum.Failed;
}

/**
* Returns whether the Staking operation is in a complete state.
*
* @returns Whether the Staking operation is in a complete state.
*/
isComplete(): boolean {
return this.getStatus() === StakingOperationStatusEnum.Complete;
}

Expand Down
4 changes: 1 addition & 3 deletions src/coinbase/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { parseUnsignedPayload } from "./utils";
export class Transaction {
private model: TransactionModel;
private raw?: ethers.Transaction;
private signed: boolean | undefined;

/**
* Transactions should be constructed via higher level abstractions like Trade or Transfer.
Expand Down Expand Up @@ -136,7 +135,6 @@ export class Transaction {
async sign(key: ethers.Wallet) {
const signedPayload = await key!.signTransaction(this.rawTransaction());
this.model.signed_payload = signedPayload;
this.signed = true;
// Removes the '0x' prefix as required by the API.
return signedPayload.slice(2);
}
Expand All @@ -147,7 +145,7 @@ export class Transaction {
* @returns if the transaction has been signed.
*/
isSigned(): boolean | undefined {
return this.signed;
return !!this.model.signed_payload;
}

/**
Expand Down

0 comments on commit 340c675

Please sign in to comment.