Skip to content
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

## [0.24.0] - 2025-05-06

- Add support for execution layer consolidations post Pectra.

## [0.23.0] - 2025-04-16

- Add support for both consensus and execution based withdrawals post-pectra.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"license": "ISC",
"description": "Coinbase Platform SDK",
"repository": "https://github.com/coinbase/coinbase-sdk-nodejs",
"version": "0.23.0",
"version": "0.24.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion quickstart-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"dependencies": {
"@solana/web3.js": "^2.0.0-rc.1",
"bs58": "^6.0.0",
"@coinbase/coinbase-sdk": "^0.23.0",
"@coinbase/coinbase-sdk": "^0.24.0",
"csv-parse": "^5.5.6",
"csv-writer": "^1.6.0",
"viem": "^2.21.6"
Expand Down
23 changes: 14 additions & 9 deletions src/coinbase/address/external_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,19 @@ export class ExternalAddress extends Address {
return this.buildStakingOperation(amount, assetId, "claim_stake", mode, options);
}

/**
* Builds a validator consolidation operation to help consolidate validators post Pectra.
*
* @param options - Additional options for the validator consolidation operation.
*
* @returns The validator consolidation operation.
*/
public async buildValidatorConsolidationOperation(
options: { [key: string]: string } = {},
): Promise<StakingOperation> {
return this.buildStakingOperation(0, "eth", "consolidate", StakeOptionsMode.NATIVE, options);
}

/**
* Builds the staking operation based on the supplied input.
*
Expand All @@ -119,15 +132,7 @@ export class ExternalAddress extends Address {

newOptions.mode = mode;

// If performing a native eth unstake v2, the amount is not required.
if (!IsDedicatedEthUnstakeV2Operation(assetId, action, mode, newOptions)) {
const stakingAmount = new Decimal(amount.toString());
if (stakingAmount.lessThanOrEqualTo(0)) {
throw new Error(`Amount required greater than zero.`);
}

newOptions.amount = asset.toAtomicAmount(new Decimal(amount.toString())).toString();
}
newOptions.amount = asset.toAtomicAmount(new Decimal(amount.toString())).toString();

const request = {
network_id: this.getNetworkId(),
Expand Down
38 changes: 27 additions & 11 deletions src/coinbase/address/wallet_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,32 @@ export class WalletAddress extends Address {
);
}

/**
* Creates a staking operation to consolidate.
*
* @param options - Additional options for the consolidation operation.
*
* @param timeoutSeconds - The amount to wait for the transaction to complete when broadcasted.
* @param intervalSeconds - The amount to check each time for a successful broadcast.
*
* @returns The staking operation after it's completed successfully.
*/
public async createValidatorConsolidation(
options: { [key: string]: string } = {},
timeoutSeconds = 600,
intervalSeconds = 0.2,
): Promise<StakingOperation> {
return this.createStakingOperation(
0,
"eth",
"consolidate",
StakeOptionsMode.NATIVE,
options,
timeoutSeconds,
intervalSeconds,
);
}

/**
* Creates a Payload Signature.
*
Expand Down Expand Up @@ -1011,13 +1037,6 @@ export class WalletAddress extends Address {
timeoutSeconds: number,
intervalSeconds: number,
): Promise<StakingOperation> {
// If performing a native ETH unstake, the amount is not required.
if (!IsDedicatedEthUnstakeV2Operation(assetId, action, mode, options)) {
if (new Decimal(amount.toString()).lessThanOrEqualTo(0)) {
throw new Error("Amount required greater than zero.");
}
}

let stakingOperation = await this.createStakingOperationRequest(
amount,
assetId,
Expand Down Expand Up @@ -1080,10 +1099,7 @@ export class WalletAddress extends Address {

options.mode = mode ? mode : StakeOptionsMode.DEFAULT;

// If performing a native ETH unstake, the amount is not required.
if (!IsDedicatedEthUnstakeV2Operation(assetId, action, mode, options)) {
options.amount = asset.toAtomicAmount(new Decimal(amount.toString())).toString();
}
options.amount = asset.toAtomicAmount(new Decimal(amount.toString())).toString();

const stakingOperationRequest = {
network_id: this.getNetworkId(),
Expand Down
4 changes: 2 additions & 2 deletions src/tests/authenticator_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe("Authenticator tests", () => {
const config = await authenticator.authenticateRequest(VALID_CONFIG, true);
const correlationContext = config.headers["Correlation-Context"] as string;
expect(correlationContext).toContain(
"sdk_version=0.23.0,sdk_language=typescript,source=mockSource",
"sdk_version=0.24.0,sdk_language=typescript,source=mockSource",
);
});
});
Expand Down Expand Up @@ -204,7 +204,7 @@ describe("Authenticator tests for Edwards key", () => {
const config = await authenticator.authenticateRequest(VALID_CONFIG, true);
const correlationContext = config.headers["Correlation-Context"] as string;
expect(correlationContext).toContain(
"sdk_version=0.23.0,sdk_language=typescript,source=mockSource",
"sdk_version=0.24.0,sdk_language=typescript,source=mockSource",
);
});
});
Expand Down
Loading