Skip to content

Commit

Permalink
fix: deposit data root calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
failingtwice committed Jan 21, 2025
1 parent cfef66c commit da66162
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 52 deletions.
29 changes: 29 additions & 0 deletions lib/deposit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { sha256 } from "ethers";

Check failure on line 1 in lib/deposit.ts

View workflow job for this annotation

GitHub Actions / ESLint

Run autofix to sort these imports!
import { ONE_GWEI } from "./constants";
import { bigintToHex } from "bigint-conversion";
import { intToHex } from "ethereumjs-util";

Check warning on line 4 in lib/deposit.ts

View workflow job for this annotation

GitHub Actions / ESLint

'intToHex' is defined but never used

export function computeDepositDataRoot(creds: string, pubkey: string, signature: string, amount: bigint) {
// strip everything of the 0x prefix to make 0x explicit when slicing
creds = creds.slice(2);
pubkey = pubkey.slice(2);
signature = signature.slice(2);

const pubkeyRoot = sha256("0x" + pubkey + "00".repeat(16)).slice(2);

const sigSlice1root = sha256("0x" + signature.slice(0, 128)).slice(2);
const sigSlice2root = sha256("0x" + signature.slice(128, signature.length) + "00".repeat(32)).slice(2);
const sigRoot = sha256("0x" + sigSlice1root + sigSlice2root).slice(2);

const sizeInGweiLE64 = formatAmount(amount);

const pubkeyCredsRoot = sha256("0x" + pubkeyRoot + creds).slice(2);
const sizeSigRoot = sha256("0x" + sizeInGweiLE64 + "00".repeat(24) + sigRoot).slice(2);
return sha256("0x" + pubkeyCredsRoot + sizeSigRoot);
}

export function formatAmount(amount: bigint) {
const gweiAmount = amount / ONE_GWEI;
let bytes = bigintToHex(gweiAmount, false, 8);

Check failure on line 27 in lib/deposit.ts

View workflow job for this annotation

GitHub Actions / ESLint

'bytes' is never reassigned. Use 'const' instead
return Buffer.from(bytes, "hex").reverse().toString("hex");
}
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ export * from "./time";
export * from "./transaction";
export * from "./type";
export * from "./units";
export * from "./deposit";
28 changes: 2 additions & 26 deletions test/0.8.25/vaults/staking-vault/staking-vault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
VaultHub__MockForStakingVault,
} from "typechain-types";

import { de0x, ether, findEvents, impersonate, streccak } from "lib";
import { computeDepositDataRoot, de0x, ether, findEvents, impersonate, streccak } from "lib";

import { Snapshot } from "test/suite";

Expand Down Expand Up @@ -329,7 +329,7 @@ describe("StakingVault", () => {
const signature = "0x" + "ef".repeat(96);
const amount = ether("32");
const withdrawalCredentials = await stakingVault.withdrawalCredentials();
const depositDataRoot = getRoot(withdrawalCredentials, pubkey, signature, amount);
const depositDataRoot = computeDepositDataRoot(withdrawalCredentials, pubkey, signature, amount);

await expect(
stakingVault.connect(operator).depositToBeaconChain([{ pubkey, signature, amount, depositDataRoot }]),
Expand Down Expand Up @@ -499,27 +499,3 @@ describe("StakingVault", () => {
return [stakingVault_, vaultHub_, vaultFactory_, stakingVaultImplementation_, depositContract_];
}
});

function getRoot(creds: string, pubkey: string, signature: string, size: bigint) {
// strip everything of the 0x prefix to make 0x explicit when slicing
creds = creds.slice(2);
pubkey = pubkey.slice(2);
signature = signature.slice(2);
const sizeHex = size.toString(16);

const pubkeyRoot = keccak256("0x" + pubkey + "00".repeat(16)).slice(2);
const sigSlice1root = keccak256("0x" + signature.slice(0, 128)).slice(2);
const sigSlice2root = keccak256("0x" + signature.slice(128, signature.length) + "00".repeat(32)).slice(2);
const sigRoot = keccak256("0x" + sigSlice1root + sigSlice2root).slice(2);
const sizeInGweiLE64 = toLittleEndian(sizeHex);

const pubkeyCredsRoot = keccak256("0x" + pubkeyRoot + creds).slice(2);
const sizeSigRoot = keccak256("0x" + sizeInGweiLE64 + "00".repeat(24) + sigRoot).slice(2);

return keccak256("0x" + pubkeyCredsRoot + sizeSigRoot);
}

function toLittleEndian(value: string) {
const bytes = Buffer.from(value, "hex");
return bytes.reverse().toString("hex");
}
28 changes: 2 additions & 26 deletions test/integration/vaults-happy-path.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";

import { Delegation, StakingVault } from "typechain-types";

import { impersonate, log, streccak, trace, updateBalance } from "lib";
import { computeDepositDataRoot, impersonate, log, streccak, trace, updateBalance } from "lib";

Check warning on line 9 in test/integration/vaults-happy-path.integration.ts

View workflow job for this annotation

GitHub Actions / ESLint

'streccak' is defined but never used
import { getProtocolContext, ProtocolContext } from "lib/protocol";
import {
getReportTimeElapsed,
Expand Down Expand Up @@ -258,7 +258,7 @@ describe("Scenario: Staking Vaults Happy Path", () => {
pubkey: pubkey,
signature: signature,
amount: VALIDATOR_DEPOSIT_SIZE,
depositDataRoot: getRoot(withdrawalCredentials, pubkey, signature, VALIDATOR_DEPOSIT_SIZE),
depositDataRoot: computeDepositDataRoot(withdrawalCredentials, pubkey, signature, VALIDATOR_DEPOSIT_SIZE),
});
}

Expand Down Expand Up @@ -475,27 +475,3 @@ describe("Scenario: Staking Vaults Happy Path", () => {
expect(await stakingVault.locked()).to.equal(0);
});
});

function getRoot(creds: string, pubkey: string, signature: string, size: bigint) {
// strip everything of the 0x prefix to make 0x explicit when slicing
creds = creds.slice(2);
pubkey = pubkey.slice(2);
signature = signature.slice(2);
const sizeHex = size.toString(16);

const pubkeyRoot = keccak256("0x" + pubkey + "00".repeat(16)).slice(2);
const sigSlice1root = keccak256("0x" + signature.slice(0, 128)).slice(2);
const sigSlice2root = keccak256("0x" + signature.slice(128, signature.length) + "00".repeat(32)).slice(2);
const sigRoot = keccak256("0x" + sigSlice1root + sigSlice2root).slice(2);
const sizeInGweiLE64 = toLittleEndian(sizeHex);

const pubkeyCredsRoot = keccak256("0x" + pubkeyRoot + creds).slice(2);
const sizeSigRoot = keccak256("0x" + sizeInGweiLE64 + "00".repeat(24) + sigRoot).slice(2);

return keccak256("0x" + pubkeyCredsRoot + sizeSigRoot);
}

function toLittleEndian(value: string) {
const bytes = Buffer.from(value, "hex");
return bytes.reverse().toString("hex");
}

0 comments on commit da66162

Please sign in to comment.