ethers.js
ethers.js copied to clipboard
option to keep padding for quantities
Allows to optionally keep the leading 0
s when converting a value to a Quantity.
That’s what hexlify
does; it doesn’t remove leading 0’s. A “quantity” type forbids leading 0’s, which is the purpose of that function, but if you use hexlify
it will retain the zeros.
What do you need this functionality for?
for instance when a number needs to be represented by all 32 bytes but there are leading 0
s in the hex number
take this example:
> num = BigInt('0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d')
1937035142596246788172577232054709726386880441279550832067530347910661804397n
> ethers.hexlify(num)
Uncaught:
TypeError: invalid BytesLike value (argument="value", value=1937035142596246788172577232054709726386880441279550832067530347910661804397, code=INVALID_ARGUMENT, version=6.8.0)
at makeError (./node_modules/ethers/lib.commonjs/utils/errors.js:122:21)
at assert (./node_modules/ethers/lib.commonjs/utils/errors.js:149:15)
at assertArgument (./node_modules/ethers/lib.commonjs/utils/errors.js:161:5)
at _getBytes (./node_modules/ethers/lib.commonjs/utils/data.js:27:36)
at getBytes (./node_modules/ethers/lib.commonjs/utils/data.js:37:12)
at Object.hexlify (./node_modules/ethers/lib.commonjs/utils/data.js:84:19) {
code: 'INVALID_ARGUMENT',
argument: 'value',
value: 1937035142596246788172577232054709726386880441279550832067530347910661804397n,
shortMessage: 'invalid BytesLike value'
}
> ethers.toQuantity(num)
'0x44852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d'
-
hexlify
throws an error because its an odd number of bytes (leading0
) -
toQuantity
strips the 0 making the number an odd number of bytes
I need all 32 bytes to be populated when converting an ENS token ID from a decimal number into a hex which represents the token's labelhash
this is not trivial to ensure I have the correct value but becomes annoying when you need to remember this 1 edge case and reproduce the following code to work:
const q = ethers.toQuantity(opts.tokenId)
const labelhash = ethers.zeroPadValue(q.length % 2 ? `0x0${q.substring(2)}` : q, 32)
const url = 'https://api.thegraph.com/subgraphs/name/ensdomains/ens'
const res: { registrations: [ { domain: { name: string } } | undefined ] } = await request(url, gql`
query {
registrations(
where: { domain_: { labelhash: "${labelhash}" } }
) { domain { name } }
}`,
)
iirc in v5 hexlify
did not throw an error and did exactly want I wanted
In v5, hexlify accepted a numeric type; the equivalent in v6 is toBeArray
, to be more explicit about how input types should be processed.
It also isn’t safe to use v5 hexlify to get a 32-byte value from a bigint; it might usually work out (because of how hashing works, often having non-zero values in high-order bits), but if for example the hex string were to begin with 0x000
the final string would be only 31 bytes wide.
For now, I think you would want zeroPadValue(toBeArray(value), 32)
to ensure you get a 32 byte (64 nibble) hex string.
It may make sense for zeroPadValue
to accept a BigInt or number as well, though.
You can also use abiCoder.encode([ "uint" ], [ value ])
. Whatever best conveys the intention of the code, is best. :)