-
Notifications
You must be signed in to change notification settings - Fork 760
/
withdrawal.ts
131 lines (119 loc) · 4.44 KB
/
withdrawal.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { Address } from './address.js'
import { bigIntToHex, bytesToHex, toBytes } from './bytes.js'
import { BIGINT_0 } from './constants.js'
import { TypeOutput, toType } from './types.js'
import type { AddressLike, BigIntLike, PrefixedHexString } from './types.js'
/**
* Flexible input data type for EIP-4895 withdrawal data with amount in Gwei to
* match CL representation and for eventual ssz withdrawalsRoot
*/
export type WithdrawalData = {
index: BigIntLike
validatorIndex: BigIntLike
address: AddressLike
amount: BigIntLike
}
/**
* JSON RPC interface for EIP-4895 withdrawal data with amount in Gwei to
* match CL representation and for eventual ssz withdrawalsRoot
*/
export interface JSONRPCWithdrawal {
index: PrefixedHexString // QUANTITY - bigint 8 bytes
validatorIndex: PrefixedHexString // QUANTITY - bigint 8 bytes
address: PrefixedHexString // DATA, 20 Bytes address to withdraw to
amount: PrefixedHexString // QUANTITY - bigint amount in Gwei 8 bytes
}
export type WithdrawalBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array]
/**
* Convert a withdrawal to a byte array
* @param withdrawal the withdrawal to convert
* @returns byte array of the withdrawal
*/
export function withdrawalToBytesArray(withdrawal: Withdrawal | WithdrawalData): WithdrawalBytes {
const { index, validatorIndex, address, amount } = withdrawal
const indexBytes =
toType(index, TypeOutput.BigInt) === BIGINT_0
? new Uint8Array()
: toType(index, TypeOutput.Uint8Array)
const validatorIndexBytes =
toType(validatorIndex, TypeOutput.BigInt) === BIGINT_0
? new Uint8Array()
: toType(validatorIndex, TypeOutput.Uint8Array)
const addressBytes =
address instanceof Address ? (<Address>address).bytes : toType(address, TypeOutput.Uint8Array)
const amountBytes =
toType(amount, TypeOutput.BigInt) === BIGINT_0
? new Uint8Array()
: toType(amount, TypeOutput.Uint8Array)
return [indexBytes, validatorIndexBytes, addressBytes, amountBytes]
}
/**
* Representation of EIP-4895 withdrawal data
*/
export class Withdrawal {
/**
* This constructor assigns and validates the values.
* Use the static factory methods to assist in creating a Withdrawal object from varying data types.
* Its amount is in Gwei to match CL representation and for eventual ssz withdrawalsRoot
*/
constructor(
public readonly index: bigint,
public readonly validatorIndex: bigint,
public readonly address: Address,
/**
* withdrawal amount in Gwei to match the CL representation and eventually ssz withdrawalsRoot
*/
public readonly amount: bigint,
) {}
raw() {
return withdrawalToBytesArray(this)
}
toValue() {
return {
index: this.index,
validatorIndex: this.validatorIndex,
address: this.address.bytes,
amount: this.amount,
}
}
toJSON() {
return {
index: bigIntToHex(this.index),
validatorIndex: bigIntToHex(this.validatorIndex),
address: bytesToHex(this.address.bytes),
amount: bigIntToHex(this.amount),
}
}
}
/**
* Creates a validator withdrawal request to be submitted to the consensus layer
* @param withdrawalData the consensus layer index and validator index values for the
* validator requesting the withdrawal and the address and withdrawal amount of the request
* @returns a {@link Withdrawal} object
*/
export function createWithdrawal(withdrawalData: WithdrawalData) {
const {
index: indexData,
validatorIndex: validatorIndexData,
address: addressData,
amount: amountData,
} = withdrawalData
const index = toType(indexData, TypeOutput.BigInt)
const validatorIndex = toType(validatorIndexData, TypeOutput.BigInt)
const address = addressData instanceof Address ? addressData : new Address(toBytes(addressData))
const amount = toType(amountData, TypeOutput.BigInt)
return new Withdrawal(index, validatorIndex, address, amount)
}
/**
* Creates a validator withdrawal request to be submitted to the consensus layer from
* an RLP list
* @param withdrawalArray decoded RLP list of withdrawal data elements
* @returns a {@link Withdrawal} object
*/
export function createWithdrawalFromBytesArray(withdrawalArray: WithdrawalBytes) {
if (withdrawalArray.length !== 4) {
throw Error(`Invalid withdrawalArray length expected=4 actual=${withdrawalArray.length}`)
}
const [index, validatorIndex, address, amount] = withdrawalArray
return createWithdrawal({ index, validatorIndex, address, amount })
}