@rocketh/signer 0.10.5 → 0.10.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/dist/index.cjs +902 -882
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +902 -882
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
package/dist/index.mjs
CHANGED
|
@@ -2756,7 +2756,7 @@ function checksum(len, fn) {
|
|
|
2756
2756
|
// -----------
|
|
2757
2757
|
const genBase58 = (abc) => chain(radix(58), alphabet(abc), join(''));
|
|
2758
2758
|
const base58 = /* @__PURE__ */ genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
|
2759
|
-
const createBase58check =
|
|
2759
|
+
const createBase58check = (sha256) => chain(checksum(4, (data) => sha256(sha256(data))), base58);
|
|
2760
2760
|
// legacy export, bad name
|
|
2761
2761
|
const base58check$1 = createBase58check;
|
|
2762
2762
|
|
|
@@ -3096,7 +3096,7 @@ function mnemonicToSeedSync(mnemonic, passphrase = '') {
|
|
|
3096
3096
|
return pbkdf2(sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
|
|
3097
3097
|
}
|
|
3098
3098
|
|
|
3099
|
-
const version = '2.
|
|
3099
|
+
const version = '2.16.2';
|
|
3100
3100
|
|
|
3101
3101
|
const getVersion = () => `viem@${version}`;
|
|
3102
3102
|
|
|
@@ -3153,7 +3153,7 @@ class BaseError extends Error {
|
|
|
3153
3153
|
...(args.metaMessages ? [...args.metaMessages, ''] : []),
|
|
3154
3154
|
...(docsPath
|
|
3155
3155
|
? [
|
|
3156
|
-
`Docs: https://viem.sh${docsPath}${args.docsSlug ? `#${args.docsSlug}` : ''}`,
|
|
3156
|
+
`Docs: ${args.docsBaseUrl ?? 'https://viem.sh'}${docsPath}${args.docsSlug ? `#${args.docsSlug}` : ''}`,
|
|
3157
3157
|
]
|
|
3158
3158
|
: []),
|
|
3159
3159
|
...(details ? [`Details: ${details}`] : []),
|
|
@@ -3950,12 +3950,24 @@ function keccak256(value, to_) {
|
|
|
3950
3950
|
return toHex(bytes);
|
|
3951
3951
|
}
|
|
3952
3952
|
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3953
|
+
const checksumAddressCache = /*#__PURE__*/ new LruMap(8192);
|
|
3954
|
+
function checksumAddress(address_,
|
|
3955
|
+
/**
|
|
3956
|
+
* Warning: EIP-1191 checksum addresses are generally not backwards compatible with the
|
|
3957
|
+
* wider Ethereum ecosystem, meaning it will break when validated against an application/tool
|
|
3958
|
+
* that relies on EIP-55 checksum encoding (checksum without chainId).
|
|
3959
|
+
*
|
|
3960
|
+
* It is highly recommended to not use this feature unless you
|
|
3961
|
+
* know what you are doing.
|
|
3962
|
+
*
|
|
3963
|
+
* See more: https://github.com/ethereum/EIPs/issues/1121
|
|
3964
|
+
*/
|
|
3965
|
+
chainId) {
|
|
3966
|
+
if (checksumAddressCache.has(`${address_}.${chainId}`))
|
|
3967
|
+
return checksumAddressCache.get(`${address_}.${chainId}`);
|
|
3968
|
+
const hexAddress = address_.substring(2).toLowerCase();
|
|
3957
3969
|
const hash = keccak256(stringToBytes(hexAddress), 'bytes');
|
|
3958
|
-
const address = (
|
|
3970
|
+
const address = (hexAddress).split('');
|
|
3959
3971
|
for (let i = 0; i < 40; i += 2) {
|
|
3960
3972
|
if (hash[i >> 1] >> 4 >= 8 && address[i]) {
|
|
3961
3973
|
address[i] = address[i].toUpperCase();
|
|
@@ -3964,15 +3976,19 @@ function checksumAddress(address_, chainId) {
|
|
|
3964
3976
|
address[i + 1] = address[i + 1].toUpperCase();
|
|
3965
3977
|
}
|
|
3966
3978
|
}
|
|
3967
|
-
|
|
3979
|
+
const result = `0x${address.join('')}`;
|
|
3980
|
+
checksumAddressCache.set(`${address_}.${chainId}`, result);
|
|
3981
|
+
return result;
|
|
3968
3982
|
}
|
|
3969
3983
|
|
|
3970
3984
|
const addressRegex = /^0x[a-fA-F0-9]{40}$/;
|
|
3985
|
+
/** @internal */
|
|
3971
3986
|
const isAddressCache = /*#__PURE__*/ new LruMap(8192);
|
|
3972
3987
|
function isAddress(address, options) {
|
|
3973
3988
|
const { strict = true } = options ?? {};
|
|
3974
|
-
|
|
3975
|
-
|
|
3989
|
+
const cacheKey = `${address}.${strict}`;
|
|
3990
|
+
if (isAddressCache.has(cacheKey))
|
|
3991
|
+
return isAddressCache.get(cacheKey);
|
|
3976
3992
|
const result = (() => {
|
|
3977
3993
|
if (!addressRegex.test(address))
|
|
3978
3994
|
return false;
|
|
@@ -3982,7 +3998,7 @@ function isAddress(address, options) {
|
|
|
3982
3998
|
return checksumAddress(address) === address;
|
|
3983
3999
|
return true;
|
|
3984
4000
|
})();
|
|
3985
|
-
isAddressCache.set(
|
|
4001
|
+
isAddressCache.set(cacheKey, result);
|
|
3986
4002
|
return result;
|
|
3987
4003
|
}
|
|
3988
4004
|
|
|
@@ -4004,6 +4020,7 @@ function toAccount(source) {
|
|
|
4004
4020
|
throw new InvalidAddressError({ address: source.address });
|
|
4005
4021
|
return {
|
|
4006
4022
|
address: source.address,
|
|
4023
|
+
nonceManager: source.nonceManager,
|
|
4007
4024
|
signMessage: source.signMessage,
|
|
4008
4025
|
signTransaction: source.signTransaction,
|
|
4009
4026
|
signTypedData: source.signTypedData,
|
|
@@ -4048,16 +4065,20 @@ function concatHex(values) {
|
|
|
4048
4065
|
return `0x${values.reduce((acc, x) => acc + x.replace('0x', ''), '')}`;
|
|
4049
4066
|
}
|
|
4050
4067
|
|
|
4051
|
-
function
|
|
4052
|
-
const
|
|
4053
|
-
if (typeof
|
|
4054
|
-
return
|
|
4055
|
-
if (
|
|
4056
|
-
return
|
|
4057
|
-
return
|
|
4068
|
+
function toPrefixedMessage(message_) {
|
|
4069
|
+
const message = (() => {
|
|
4070
|
+
if (typeof message_ === 'string')
|
|
4071
|
+
return stringToHex(message_);
|
|
4072
|
+
if (typeof message_.raw === 'string')
|
|
4073
|
+
return message_.raw;
|
|
4074
|
+
return bytesToHex(message_.raw);
|
|
4058
4075
|
})();
|
|
4059
|
-
const
|
|
4060
|
-
return
|
|
4076
|
+
const prefix = stringToHex(`${presignMessagePrefix}${size(message)}`);
|
|
4077
|
+
return concat([prefix, message]);
|
|
4078
|
+
}
|
|
4079
|
+
|
|
4080
|
+
function hashMessage(message, to_) {
|
|
4081
|
+
return keccak256(toPrefixedMessage(message), to_);
|
|
4061
4082
|
}
|
|
4062
4083
|
|
|
4063
4084
|
/**
|
|
@@ -4067,22 +4088,22 @@ function hashMessage(message, to_) {
|
|
|
4067
4088
|
* @returns The signature in hex format.
|
|
4068
4089
|
*
|
|
4069
4090
|
* @example
|
|
4070
|
-
*
|
|
4091
|
+
* serializeSignature({
|
|
4071
4092
|
* r: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf',
|
|
4072
4093
|
* s: '0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8',
|
|
4073
4094
|
* yParity: 1
|
|
4074
4095
|
* })
|
|
4075
4096
|
* // "0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c"
|
|
4076
4097
|
*/
|
|
4077
|
-
function
|
|
4078
|
-
const
|
|
4079
|
-
if (
|
|
4080
|
-
return
|
|
4081
|
-
if (v ===
|
|
4082
|
-
return
|
|
4083
|
-
throw new Error('Invalid v value');
|
|
4098
|
+
function serializeSignature({ r, s, v, yParity }) {
|
|
4099
|
+
const yParity_ = (() => {
|
|
4100
|
+
if (yParity === 0 || yParity === 1)
|
|
4101
|
+
return yParity;
|
|
4102
|
+
if (v && (v === 27n || v === 28n || v >= 35n))
|
|
4103
|
+
return v % 2n === 0n ? 1 : 0;
|
|
4104
|
+
throw new Error('Invalid `v` or `yParity` value');
|
|
4084
4105
|
})();
|
|
4085
|
-
return `0x${new secp256k1.Signature(hexToBigInt(r), hexToBigInt(s)).toCompactHex()}${
|
|
4106
|
+
return `0x${new secp256k1.Signature(hexToBigInt(r), hexToBigInt(s)).toCompactHex()}${yParity_ === 0 ? '1b' : '1c'}`;
|
|
4086
4107
|
}
|
|
4087
4108
|
|
|
4088
4109
|
// TODO(v3): Convert to sync.
|
|
@@ -4112,7 +4133,7 @@ async function sign({ hash, privateKey, }) {
|
|
|
4112
4133
|
*/
|
|
4113
4134
|
async function signMessage({ message, privateKey, }) {
|
|
4114
4135
|
const signature = await sign({ hash: hashMessage(message), privateKey });
|
|
4115
|
-
return
|
|
4136
|
+
return serializeSignature(signature);
|
|
4116
4137
|
}
|
|
4117
4138
|
|
|
4118
4139
|
const gweiUnits = {
|
|
@@ -4284,11 +4305,8 @@ function blobsToProofs(parameters) {
|
|
|
4284
4305
|
}
|
|
4285
4306
|
|
|
4286
4307
|
function sha256(value, to_) {
|
|
4287
|
-
const to = to_ || 'hex';
|
|
4288
4308
|
const bytes = sha256$1(isHex(value, { strict: false }) ? toBytes(value) : value);
|
|
4289
|
-
|
|
4290
|
-
return bytes;
|
|
4291
|
-
return toHex(bytes);
|
|
4309
|
+
return bytes;
|
|
4292
4310
|
}
|
|
4293
4311
|
|
|
4294
4312
|
/**
|
|
@@ -4311,7 +4329,7 @@ function sha256(value, to_) {
|
|
|
4311
4329
|
function commitmentToVersionedHash(parameters) {
|
|
4312
4330
|
const { commitment, version = 1 } = parameters;
|
|
4313
4331
|
const to = parameters.to ?? (typeof commitment === 'string' ? 'hex' : 'bytes');
|
|
4314
|
-
const versionedHash = sha256(commitment
|
|
4332
|
+
const versionedHash = sha256(commitment);
|
|
4315
4333
|
versionedHash.set([version], 0);
|
|
4316
4334
|
return (to === 'bytes' ? versionedHash : bytesToHex(versionedHash));
|
|
4317
4335
|
}
|
|
@@ -4364,7 +4382,6 @@ const maxBytesPerTransaction = bytesPerBlob * blobsPerTransaction -
|
|
|
4364
4382
|
1 * fieldElementsPerBlob * blobsPerTransaction;
|
|
4365
4383
|
|
|
4366
4384
|
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md#parameters
|
|
4367
|
-
/** The number of bytes in a KZG commitment. */
|
|
4368
4385
|
const versionedHashVersionKzg = 1;
|
|
4369
4386
|
|
|
4370
4387
|
class BlobSizeTooLargeError extends BaseError {
|
|
@@ -4461,7 +4478,7 @@ const staticCursor = {
|
|
|
4461
4478
|
position: 0,
|
|
4462
4479
|
positionReadCount: new Map(),
|
|
4463
4480
|
recursiveReadCount: 0,
|
|
4464
|
-
recursiveReadLimit:
|
|
4481
|
+
recursiveReadLimit: Number.POSITIVE_INFINITY,
|
|
4465
4482
|
assertReadLimit() {
|
|
4466
4483
|
if (this.recursiveReadCount >= this.recursiveReadLimit)
|
|
4467
4484
|
throw new RecursiveReadLimitExceededError({
|
|
@@ -4607,7 +4624,7 @@ const staticCursor = {
|
|
|
4607
4624
|
return () => (this.position = oldPosition);
|
|
4608
4625
|
},
|
|
4609
4626
|
_touch() {
|
|
4610
|
-
if (this.recursiveReadLimit ===
|
|
4627
|
+
if (this.recursiveReadLimit === Number.POSITIVE_INFINITY)
|
|
4611
4628
|
return;
|
|
4612
4629
|
const count = this.getReadCount();
|
|
4613
4630
|
this.positionReadCount.set(this.position, count + 1);
|
|
@@ -4718,83 +4735,153 @@ function toBlobSidecars(parameters) {
|
|
|
4718
4735
|
return sidecars;
|
|
4719
4736
|
}
|
|
4720
4737
|
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
Object.defineProperty(this, "name", {
|
|
4729
|
-
enumerable: true,
|
|
4730
|
-
configurable: true,
|
|
4731
|
-
writable: true,
|
|
4732
|
-
value: 'AbiEncodingArrayLengthMismatchError'
|
|
4733
|
-
});
|
|
4734
|
-
}
|
|
4738
|
+
function toRlp(bytes, to = 'hex') {
|
|
4739
|
+
const encodable = getEncodable(bytes);
|
|
4740
|
+
const cursor = createCursor(new Uint8Array(encodable.length));
|
|
4741
|
+
encodable.encode(cursor);
|
|
4742
|
+
if (to === 'hex')
|
|
4743
|
+
return bytesToHex(cursor.bytes);
|
|
4744
|
+
return cursor.bytes;
|
|
4735
4745
|
}
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
enumerable: true,
|
|
4741
|
-
configurable: true,
|
|
4742
|
-
writable: true,
|
|
4743
|
-
value: 'AbiEncodingBytesSizeMismatchError'
|
|
4744
|
-
});
|
|
4745
|
-
}
|
|
4746
|
+
function getEncodable(bytes) {
|
|
4747
|
+
if (Array.isArray(bytes))
|
|
4748
|
+
return getEncodableList(bytes.map((x) => getEncodable(x)));
|
|
4749
|
+
return getEncodableBytes(bytes);
|
|
4746
4750
|
}
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4751
|
+
function getEncodableList(list) {
|
|
4752
|
+
const bodyLength = list.reduce((acc, x) => acc + x.length, 0);
|
|
4753
|
+
const sizeOfBodyLength = getSizeOfLength(bodyLength);
|
|
4754
|
+
const length = (() => {
|
|
4755
|
+
if (bodyLength <= 55)
|
|
4756
|
+
return 1 + bodyLength;
|
|
4757
|
+
return 1 + sizeOfBodyLength + bodyLength;
|
|
4758
|
+
})();
|
|
4759
|
+
return {
|
|
4760
|
+
length,
|
|
4761
|
+
encode(cursor) {
|
|
4762
|
+
if (bodyLength <= 55) {
|
|
4763
|
+
cursor.pushByte(0xc0 + bodyLength);
|
|
4764
|
+
}
|
|
4765
|
+
else {
|
|
4766
|
+
cursor.pushByte(0xc0 + 55 + sizeOfBodyLength);
|
|
4767
|
+
if (sizeOfBodyLength === 1)
|
|
4768
|
+
cursor.pushUint8(bodyLength);
|
|
4769
|
+
else if (sizeOfBodyLength === 2)
|
|
4770
|
+
cursor.pushUint16(bodyLength);
|
|
4771
|
+
else if (sizeOfBodyLength === 3)
|
|
4772
|
+
cursor.pushUint24(bodyLength);
|
|
4773
|
+
else
|
|
4774
|
+
cursor.pushUint32(bodyLength);
|
|
4775
|
+
}
|
|
4776
|
+
for (const { encode } of list) {
|
|
4777
|
+
encode(cursor);
|
|
4778
|
+
}
|
|
4779
|
+
},
|
|
4780
|
+
};
|
|
4781
|
+
}
|
|
4782
|
+
function getEncodableBytes(bytesOrHex) {
|
|
4783
|
+
const bytes = typeof bytesOrHex === 'string' ? hexToBytes(bytesOrHex) : bytesOrHex;
|
|
4784
|
+
const sizeOfBytesLength = getSizeOfLength(bytes.length);
|
|
4785
|
+
const length = (() => {
|
|
4786
|
+
if (bytes.length === 1 && bytes[0] < 0x80)
|
|
4787
|
+
return 1;
|
|
4788
|
+
if (bytes.length <= 55)
|
|
4789
|
+
return 1 + bytes.length;
|
|
4790
|
+
return 1 + sizeOfBytesLength + bytes.length;
|
|
4791
|
+
})();
|
|
4792
|
+
return {
|
|
4793
|
+
length,
|
|
4794
|
+
encode(cursor) {
|
|
4795
|
+
if (bytes.length === 1 && bytes[0] < 0x80) {
|
|
4796
|
+
cursor.pushBytes(bytes);
|
|
4797
|
+
}
|
|
4798
|
+
else if (bytes.length <= 55) {
|
|
4799
|
+
cursor.pushByte(0x80 + bytes.length);
|
|
4800
|
+
cursor.pushBytes(bytes);
|
|
4801
|
+
}
|
|
4802
|
+
else {
|
|
4803
|
+
cursor.pushByte(0x80 + 55 + sizeOfBytesLength);
|
|
4804
|
+
if (sizeOfBytesLength === 1)
|
|
4805
|
+
cursor.pushUint8(bytes.length);
|
|
4806
|
+
else if (sizeOfBytesLength === 2)
|
|
4807
|
+
cursor.pushUint16(bytes.length);
|
|
4808
|
+
else if (sizeOfBytesLength === 3)
|
|
4809
|
+
cursor.pushUint24(bytes.length);
|
|
4810
|
+
else
|
|
4811
|
+
cursor.pushUint32(bytes.length);
|
|
4812
|
+
cursor.pushBytes(bytes);
|
|
4813
|
+
}
|
|
4814
|
+
},
|
|
4815
|
+
};
|
|
4816
|
+
}
|
|
4817
|
+
function getSizeOfLength(length) {
|
|
4818
|
+
if (length < 2 ** 8)
|
|
4819
|
+
return 1;
|
|
4820
|
+
if (length < 2 ** 16)
|
|
4821
|
+
return 2;
|
|
4822
|
+
if (length < 2 ** 24)
|
|
4823
|
+
return 3;
|
|
4824
|
+
if (length < 2 ** 32)
|
|
4825
|
+
return 4;
|
|
4826
|
+
throw new BaseError('Length is too large.');
|
|
4827
|
+
}
|
|
4828
|
+
|
|
4829
|
+
class InvalidChainIdError extends BaseError {
|
|
4830
|
+
constructor({ chainId }) {
|
|
4831
|
+
super(typeof chainId === 'number'
|
|
4832
|
+
? `Chain ID "${chainId}" is invalid.`
|
|
4833
|
+
: 'Chain ID is invalid.');
|
|
4754
4834
|
Object.defineProperty(this, "name", {
|
|
4755
4835
|
enumerable: true,
|
|
4756
4836
|
configurable: true,
|
|
4757
4837
|
writable: true,
|
|
4758
|
-
value: '
|
|
4838
|
+
value: 'InvalidChainIdError'
|
|
4759
4839
|
});
|
|
4760
4840
|
}
|
|
4761
4841
|
}
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4842
|
+
|
|
4843
|
+
class FeeCapTooHighError extends BaseError {
|
|
4844
|
+
constructor({ cause, maxFeePerGas, } = {}) {
|
|
4845
|
+
super(`The fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei(maxFeePerGas)} gwei` : ''}) cannot be higher than the maximum allowed value (2^256-1).`, {
|
|
4846
|
+
cause,
|
|
4847
|
+
});
|
|
4765
4848
|
Object.defineProperty(this, "name", {
|
|
4766
4849
|
enumerable: true,
|
|
4767
4850
|
configurable: true,
|
|
4768
4851
|
writable: true,
|
|
4769
|
-
value: '
|
|
4852
|
+
value: 'FeeCapTooHigh'
|
|
4770
4853
|
});
|
|
4771
4854
|
}
|
|
4772
4855
|
}
|
|
4773
|
-
|
|
4774
|
-
|
|
4856
|
+
Object.defineProperty(FeeCapTooHighError, "nodeMessage", {
|
|
4857
|
+
enumerable: true,
|
|
4858
|
+
configurable: true,
|
|
4859
|
+
writable: true,
|
|
4860
|
+
value: /max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/
|
|
4861
|
+
});
|
|
4862
|
+
class TipAboveFeeCapError extends BaseError {
|
|
4863
|
+
constructor({ cause, maxPriorityFeePerGas, maxFeePerGas, } = {}) {
|
|
4775
4864
|
super([
|
|
4776
|
-
`
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
configurable: true,
|
|
4782
|
-
writable: true,
|
|
4783
|
-
value: 'InvalidAbiEncodingType'
|
|
4865
|
+
`The provided tip (\`maxPriorityFeePerGas\`${maxPriorityFeePerGas
|
|
4866
|
+
? ` = ${formatGwei(maxPriorityFeePerGas)} gwei`
|
|
4867
|
+
: ''}) cannot be higher than the fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei(maxFeePerGas)} gwei` : ''}).`,
|
|
4868
|
+
].join('\n'), {
|
|
4869
|
+
cause,
|
|
4784
4870
|
});
|
|
4785
|
-
}
|
|
4786
|
-
}
|
|
4787
|
-
class InvalidArrayError extends BaseError {
|
|
4788
|
-
constructor(value) {
|
|
4789
|
-
super([`Value "${value}" is not a valid array.`].join('\n'));
|
|
4790
4871
|
Object.defineProperty(this, "name", {
|
|
4791
4872
|
enumerable: true,
|
|
4792
4873
|
configurable: true,
|
|
4793
4874
|
writable: true,
|
|
4794
|
-
value: '
|
|
4875
|
+
value: 'TipAboveFeeCapError'
|
|
4795
4876
|
});
|
|
4796
4877
|
}
|
|
4797
4878
|
}
|
|
4879
|
+
Object.defineProperty(TipAboveFeeCapError, "nodeMessage", {
|
|
4880
|
+
enumerable: true,
|
|
4881
|
+
configurable: true,
|
|
4882
|
+
writable: true,
|
|
4883
|
+
value: /max priority fee per gas higher than max fee per gas|tip higher than fee cap/
|
|
4884
|
+
});
|
|
4798
4885
|
|
|
4799
4886
|
/**
|
|
4800
4887
|
* @description Returns a section of the hex or byte array given a start/end bytes offset.
|
|
@@ -4862,876 +4949,807 @@ function sliceHex(value_, start, end, { strict } = {}) {
|
|
|
4862
4949
|
return value;
|
|
4863
4950
|
}
|
|
4864
4951
|
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
* { name: 'y', type: 'uint' },
|
|
4882
|
-
* { name: 'z', type: 'bool' }
|
|
4883
|
-
* ],
|
|
4884
|
-
* ['wagmi', 420n, true]
|
|
4885
|
-
* )
|
|
4886
|
-
* ```
|
|
4887
|
-
*
|
|
4888
|
-
* You can also pass in Human Readable parameters with the parseAbiParameters utility.
|
|
4889
|
-
*
|
|
4890
|
-
* @example
|
|
4891
|
-
* ```typescript
|
|
4892
|
-
* import { encodeAbiParameters, parseAbiParameters } from 'viem'
|
|
4893
|
-
*
|
|
4894
|
-
* const encodedData = encodeAbiParameters(
|
|
4895
|
-
* parseAbiParameters('string x, uint y, bool z'),
|
|
4896
|
-
* ['wagmi', 420n, true]
|
|
4897
|
-
* )
|
|
4898
|
-
* ```
|
|
4899
|
-
*/
|
|
4900
|
-
function encodeAbiParameters(params, values) {
|
|
4901
|
-
if (params.length !== values.length)
|
|
4902
|
-
throw new AbiEncodingLengthMismatchError({
|
|
4903
|
-
expectedLength: params.length,
|
|
4904
|
-
givenLength: values.length,
|
|
4905
|
-
});
|
|
4906
|
-
// Prepare the parameters to determine dynamic types to encode.
|
|
4907
|
-
const preparedParams = prepareParams({
|
|
4908
|
-
params: params,
|
|
4909
|
-
values: values,
|
|
4910
|
-
});
|
|
4911
|
-
const data = encodeParams(preparedParams);
|
|
4912
|
-
if (data.length === 0)
|
|
4913
|
-
return '0x';
|
|
4914
|
-
return data;
|
|
4915
|
-
}
|
|
4916
|
-
function prepareParams({ params, values, }) {
|
|
4917
|
-
const preparedParams = [];
|
|
4918
|
-
for (let i = 0; i < params.length; i++) {
|
|
4919
|
-
preparedParams.push(prepareParam({ param: params[i], value: values[i] }));
|
|
4920
|
-
}
|
|
4921
|
-
return preparedParams;
|
|
4922
|
-
}
|
|
4923
|
-
function prepareParam({ param, value, }) {
|
|
4924
|
-
const arrayComponents = getArrayComponents(param.type);
|
|
4925
|
-
if (arrayComponents) {
|
|
4926
|
-
const [length, type] = arrayComponents;
|
|
4927
|
-
return encodeArray(value, { length, param: { ...param, type } });
|
|
4928
|
-
}
|
|
4929
|
-
if (param.type === 'tuple') {
|
|
4930
|
-
return encodeTuple(value, {
|
|
4931
|
-
param: param,
|
|
4932
|
-
});
|
|
4933
|
-
}
|
|
4934
|
-
if (param.type === 'address') {
|
|
4935
|
-
return encodeAddress(value);
|
|
4936
|
-
}
|
|
4937
|
-
if (param.type === 'bool') {
|
|
4938
|
-
return encodeBool(value);
|
|
4939
|
-
}
|
|
4940
|
-
if (param.type.startsWith('uint') || param.type.startsWith('int')) {
|
|
4941
|
-
const signed = param.type.startsWith('int');
|
|
4942
|
-
return encodeNumber(value, { signed });
|
|
4952
|
+
function assertTransactionEIP4844(transaction) {
|
|
4953
|
+
const { blobVersionedHashes } = transaction;
|
|
4954
|
+
if (blobVersionedHashes) {
|
|
4955
|
+
if (blobVersionedHashes.length === 0)
|
|
4956
|
+
throw new EmptyBlobError();
|
|
4957
|
+
for (const hash of blobVersionedHashes) {
|
|
4958
|
+
const size_ = size(hash);
|
|
4959
|
+
const version = hexToNumber(slice(hash, 0, 1));
|
|
4960
|
+
if (size_ !== 32)
|
|
4961
|
+
throw new InvalidVersionedHashSizeError({ hash, size: size_ });
|
|
4962
|
+
if (version !== versionedHashVersionKzg)
|
|
4963
|
+
throw new InvalidVersionedHashVersionError({
|
|
4964
|
+
hash,
|
|
4965
|
+
version,
|
|
4966
|
+
});
|
|
4967
|
+
}
|
|
4943
4968
|
}
|
|
4944
|
-
|
|
4945
|
-
|
|
4969
|
+
assertTransactionEIP1559(transaction);
|
|
4970
|
+
}
|
|
4971
|
+
function assertTransactionEIP1559(transaction) {
|
|
4972
|
+
const { chainId, maxPriorityFeePerGas, maxFeePerGas, to } = transaction;
|
|
4973
|
+
if (chainId <= 0)
|
|
4974
|
+
throw new InvalidChainIdError({ chainId });
|
|
4975
|
+
if (to && !isAddress(to))
|
|
4976
|
+
throw new InvalidAddressError({ address: to });
|
|
4977
|
+
if (maxFeePerGas && maxFeePerGas > 2n ** 256n - 1n)
|
|
4978
|
+
throw new FeeCapTooHighError({ maxFeePerGas });
|
|
4979
|
+
if (maxPriorityFeePerGas &&
|
|
4980
|
+
maxFeePerGas &&
|
|
4981
|
+
maxPriorityFeePerGas > maxFeePerGas)
|
|
4982
|
+
throw new TipAboveFeeCapError({ maxFeePerGas, maxPriorityFeePerGas });
|
|
4983
|
+
}
|
|
4984
|
+
function assertTransactionEIP2930(transaction) {
|
|
4985
|
+
const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to } = transaction;
|
|
4986
|
+
if (chainId <= 0)
|
|
4987
|
+
throw new InvalidChainIdError({ chainId });
|
|
4988
|
+
if (to && !isAddress(to))
|
|
4989
|
+
throw new InvalidAddressError({ address: to });
|
|
4990
|
+
if (maxPriorityFeePerGas || maxFeePerGas)
|
|
4991
|
+
throw new BaseError('`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid EIP-2930 Transaction attribute.');
|
|
4992
|
+
if (gasPrice && gasPrice > 2n ** 256n - 1n)
|
|
4993
|
+
throw new FeeCapTooHighError({ maxFeePerGas: gasPrice });
|
|
4994
|
+
}
|
|
4995
|
+
function assertTransactionLegacy(transaction) {
|
|
4996
|
+
const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to, accessList, } = transaction;
|
|
4997
|
+
if (to && !isAddress(to))
|
|
4998
|
+
throw new InvalidAddressError({ address: to });
|
|
4999
|
+
if (typeof chainId !== 'undefined' && chainId <= 0)
|
|
5000
|
+
throw new InvalidChainIdError({ chainId });
|
|
5001
|
+
if (maxPriorityFeePerGas || maxFeePerGas)
|
|
5002
|
+
throw new BaseError('`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid Legacy Transaction attribute.');
|
|
5003
|
+
if (gasPrice && gasPrice > 2n ** 256n - 1n)
|
|
5004
|
+
throw new FeeCapTooHighError({ maxFeePerGas: gasPrice });
|
|
5005
|
+
if (accessList)
|
|
5006
|
+
throw new BaseError('`accessList` is not a valid Legacy Transaction attribute.');
|
|
5007
|
+
}
|
|
5008
|
+
|
|
5009
|
+
function getTransactionType(transaction) {
|
|
5010
|
+
if (transaction.type)
|
|
5011
|
+
return transaction.type;
|
|
5012
|
+
if (typeof transaction.blobs !== 'undefined' ||
|
|
5013
|
+
typeof transaction.blobVersionedHashes !== 'undefined' ||
|
|
5014
|
+
typeof transaction.maxFeePerBlobGas !== 'undefined' ||
|
|
5015
|
+
typeof transaction.sidecars !== 'undefined')
|
|
5016
|
+
return 'eip4844';
|
|
5017
|
+
if (typeof transaction.maxFeePerGas !== 'undefined' ||
|
|
5018
|
+
typeof transaction.maxPriorityFeePerGas !== 'undefined') {
|
|
5019
|
+
return 'eip1559';
|
|
4946
5020
|
}
|
|
4947
|
-
if (
|
|
4948
|
-
|
|
5021
|
+
if (typeof transaction.gasPrice !== 'undefined') {
|
|
5022
|
+
if (typeof transaction.accessList !== 'undefined')
|
|
5023
|
+
return 'eip2930';
|
|
5024
|
+
return 'legacy';
|
|
4949
5025
|
}
|
|
4950
|
-
throw new
|
|
4951
|
-
docsPath: '/docs/contract/encodeAbiParameters',
|
|
4952
|
-
});
|
|
5026
|
+
throw new InvalidSerializableTransactionError({ transaction });
|
|
4953
5027
|
}
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
for (let i = 0; i <
|
|
4969
|
-
const {
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
5028
|
+
|
|
5029
|
+
/*
|
|
5030
|
+
* Serialize an EIP-2930 access list
|
|
5031
|
+
* @remarks
|
|
5032
|
+
* Use to create a transaction serializer with support for EIP-2930 access lists
|
|
5033
|
+
*
|
|
5034
|
+
* @param accessList - Array of objects of address and arrays of Storage Keys
|
|
5035
|
+
* @throws InvalidAddressError, InvalidStorageKeySizeError
|
|
5036
|
+
* @returns Array of hex strings
|
|
5037
|
+
*/
|
|
5038
|
+
function serializeAccessList(accessList) {
|
|
5039
|
+
if (!accessList || accessList.length === 0)
|
|
5040
|
+
return [];
|
|
5041
|
+
const serializedAccessList = [];
|
|
5042
|
+
for (let i = 0; i < accessList.length; i++) {
|
|
5043
|
+
const { address, storageKeys } = accessList[i];
|
|
5044
|
+
for (let j = 0; j < storageKeys.length; j++) {
|
|
5045
|
+
if (storageKeys[j].length - 2 !== 64) {
|
|
5046
|
+
throw new InvalidStorageKeySizeError({ storageKey: storageKeys[j] });
|
|
5047
|
+
}
|
|
4974
5048
|
}
|
|
4975
|
-
|
|
4976
|
-
|
|
5049
|
+
if (!isAddress(address, { strict: false })) {
|
|
5050
|
+
throw new InvalidAddressError({ address });
|
|
4977
5051
|
}
|
|
5052
|
+
serializedAccessList.push([address, storageKeys]);
|
|
4978
5053
|
}
|
|
4979
|
-
|
|
4980
|
-
return concat([...staticParams, ...dynamicParams]);
|
|
5054
|
+
return serializedAccessList;
|
|
4981
5055
|
}
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
5056
|
+
|
|
5057
|
+
function serializeTransaction(transaction, signature) {
|
|
5058
|
+
const type = getTransactionType(transaction);
|
|
5059
|
+
if (type === 'eip1559')
|
|
5060
|
+
return serializeTransactionEIP1559(transaction, signature);
|
|
5061
|
+
if (type === 'eip2930')
|
|
5062
|
+
return serializeTransactionEIP2930(transaction, signature);
|
|
5063
|
+
if (type === 'eip4844')
|
|
5064
|
+
return serializeTransactionEIP4844(transaction, signature);
|
|
5065
|
+
return serializeTransactionLegacy(transaction, signature);
|
|
4986
5066
|
}
|
|
4987
|
-
function
|
|
4988
|
-
const
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
5067
|
+
function serializeTransactionEIP4844(transaction, signature) {
|
|
5068
|
+
const { chainId, gas, nonce, to, value, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, accessList, data, } = transaction;
|
|
5069
|
+
assertTransactionEIP4844(transaction);
|
|
5070
|
+
let blobVersionedHashes = transaction.blobVersionedHashes;
|
|
5071
|
+
let sidecars = transaction.sidecars;
|
|
5072
|
+
// If `blobs` are passed, we will need to compute the KZG commitments & proofs.
|
|
5073
|
+
if (transaction.blobs &&
|
|
5074
|
+
(typeof blobVersionedHashes === 'undefined' ||
|
|
5075
|
+
typeof sidecars === 'undefined')) {
|
|
5076
|
+
const blobs = (typeof transaction.blobs[0] === 'string'
|
|
5077
|
+
? transaction.blobs
|
|
5078
|
+
: transaction.blobs.map((x) => bytesToHex(x)));
|
|
5079
|
+
const kzg = transaction.kzg;
|
|
5080
|
+
const commitments = blobsToCommitments({
|
|
5081
|
+
blobs,
|
|
5082
|
+
kzg,
|
|
4996
5083
|
});
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
if (
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
}
|
|
5005
|
-
if (dynamic || dynamicChild) {
|
|
5006
|
-
const data = encodeParams(preparedParams);
|
|
5007
|
-
if (dynamic) {
|
|
5008
|
-
const length = numberToHex(preparedParams.length, { size: 32 });
|
|
5009
|
-
return {
|
|
5010
|
-
dynamic: true,
|
|
5011
|
-
encoded: preparedParams.length > 0 ? concat([length, data]) : length,
|
|
5012
|
-
};
|
|
5084
|
+
if (typeof blobVersionedHashes === 'undefined')
|
|
5085
|
+
blobVersionedHashes = commitmentsToVersionedHashes({
|
|
5086
|
+
commitments,
|
|
5087
|
+
});
|
|
5088
|
+
if (typeof sidecars === 'undefined') {
|
|
5089
|
+
const proofs = blobsToProofs({ blobs, commitments, kzg });
|
|
5090
|
+
sidecars = toBlobSidecars({ blobs, commitments, proofs });
|
|
5013
5091
|
}
|
|
5014
|
-
if (dynamicChild)
|
|
5015
|
-
return { dynamic: true, encoded: data };
|
|
5016
5092
|
}
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5093
|
+
const serializedAccessList = serializeAccessList(accessList);
|
|
5094
|
+
const serializedTransaction = [
|
|
5095
|
+
toHex(chainId),
|
|
5096
|
+
nonce ? toHex(nonce) : '0x',
|
|
5097
|
+
maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x',
|
|
5098
|
+
maxFeePerGas ? toHex(maxFeePerGas) : '0x',
|
|
5099
|
+
gas ? toHex(gas) : '0x',
|
|
5100
|
+
to ?? '0x',
|
|
5101
|
+
value ? toHex(value) : '0x',
|
|
5102
|
+
data ?? '0x',
|
|
5103
|
+
serializedAccessList,
|
|
5104
|
+
maxFeePerBlobGas ? toHex(maxFeePerBlobGas) : '0x',
|
|
5105
|
+
blobVersionedHashes ?? [],
|
|
5106
|
+
...toYParitySignatureArray(transaction, signature),
|
|
5107
|
+
];
|
|
5108
|
+
const blobs = [];
|
|
5109
|
+
const commitments = [];
|
|
5110
|
+
const proofs = [];
|
|
5111
|
+
if (sidecars)
|
|
5112
|
+
for (let i = 0; i < sidecars.length; i++) {
|
|
5113
|
+
const { blob, commitment, proof } = sidecars[i];
|
|
5114
|
+
blobs.push(blob);
|
|
5115
|
+
commitments.push(commitment);
|
|
5116
|
+
proofs.push(proof);
|
|
5117
|
+
}
|
|
5118
|
+
return concatHex([
|
|
5119
|
+
'0x03',
|
|
5120
|
+
sidecars
|
|
5121
|
+
? // If sidecars are enabled, envelope turns into a "wrapper":
|
|
5122
|
+
toRlp([serializedTransaction, blobs, commitments, proofs])
|
|
5123
|
+
: // If sidecars are disabled, standard envelope is used:
|
|
5124
|
+
toRlp(serializedTransaction),
|
|
5125
|
+
]);
|
|
5021
5126
|
}
|
|
5022
|
-
function
|
|
5023
|
-
const
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
value,
|
|
5043
|
-
});
|
|
5044
|
-
return { dynamic: false, encoded: padHex(value, { dir: 'right' }) };
|
|
5045
|
-
}
|
|
5046
|
-
function encodeBool(value) {
|
|
5047
|
-
if (typeof value !== 'boolean')
|
|
5048
|
-
throw new BaseError(`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`);
|
|
5049
|
-
return { dynamic: false, encoded: padHex(boolToHex(value)) };
|
|
5127
|
+
function serializeTransactionEIP1559(transaction, signature) {
|
|
5128
|
+
const { chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, data, } = transaction;
|
|
5129
|
+
assertTransactionEIP1559(transaction);
|
|
5130
|
+
const serializedAccessList = serializeAccessList(accessList);
|
|
5131
|
+
const serializedTransaction = [
|
|
5132
|
+
toHex(chainId),
|
|
5133
|
+
nonce ? toHex(nonce) : '0x',
|
|
5134
|
+
maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x',
|
|
5135
|
+
maxFeePerGas ? toHex(maxFeePerGas) : '0x',
|
|
5136
|
+
gas ? toHex(gas) : '0x',
|
|
5137
|
+
to ?? '0x',
|
|
5138
|
+
value ? toHex(value) : '0x',
|
|
5139
|
+
data ?? '0x',
|
|
5140
|
+
serializedAccessList,
|
|
5141
|
+
...toYParitySignatureArray(transaction, signature),
|
|
5142
|
+
];
|
|
5143
|
+
return concatHex([
|
|
5144
|
+
'0x02',
|
|
5145
|
+
toRlp(serializedTransaction),
|
|
5146
|
+
]);
|
|
5050
5147
|
}
|
|
5051
|
-
function
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5148
|
+
function serializeTransactionEIP2930(transaction, signature) {
|
|
5149
|
+
const { chainId, gas, data, nonce, to, value, accessList, gasPrice } = transaction;
|
|
5150
|
+
assertTransactionEIP2930(transaction);
|
|
5151
|
+
const serializedAccessList = serializeAccessList(accessList);
|
|
5152
|
+
const serializedTransaction = [
|
|
5153
|
+
toHex(chainId),
|
|
5154
|
+
nonce ? toHex(nonce) : '0x',
|
|
5155
|
+
gasPrice ? toHex(gasPrice) : '0x',
|
|
5156
|
+
gas ? toHex(gas) : '0x',
|
|
5157
|
+
to ?? '0x',
|
|
5158
|
+
value ? toHex(value) : '0x',
|
|
5159
|
+
data ?? '0x',
|
|
5160
|
+
serializedAccessList,
|
|
5161
|
+
...toYParitySignatureArray(transaction, signature),
|
|
5162
|
+
];
|
|
5163
|
+
return concatHex([
|
|
5164
|
+
'0x01',
|
|
5165
|
+
toRlp(serializedTransaction),
|
|
5166
|
+
]);
|
|
5059
5167
|
}
|
|
5060
|
-
function
|
|
5061
|
-
const
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5168
|
+
function serializeTransactionLegacy(transaction, signature) {
|
|
5169
|
+
const { chainId = 0, gas, data, nonce, to, value, gasPrice } = transaction;
|
|
5170
|
+
assertTransactionLegacy(transaction);
|
|
5171
|
+
let serializedTransaction = [
|
|
5172
|
+
nonce ? toHex(nonce) : '0x',
|
|
5173
|
+
gasPrice ? toHex(gasPrice) : '0x',
|
|
5174
|
+
gas ? toHex(gas) : '0x',
|
|
5175
|
+
to ?? '0x',
|
|
5176
|
+
value ? toHex(value) : '0x',
|
|
5177
|
+
data ?? '0x',
|
|
5178
|
+
];
|
|
5179
|
+
if (signature) {
|
|
5180
|
+
const v = (() => {
|
|
5181
|
+
// EIP-155 (inferred chainId)
|
|
5182
|
+
if (signature.v >= 35n) {
|
|
5183
|
+
const inferredChainId = (signature.v - 35n) / 2n;
|
|
5184
|
+
if (inferredChainId > 0)
|
|
5185
|
+
return signature.v;
|
|
5186
|
+
return 27n + (signature.v === 35n ? 0n : 1n);
|
|
5187
|
+
}
|
|
5188
|
+
// EIP-155 (explicit chainId)
|
|
5189
|
+
if (chainId > 0)
|
|
5190
|
+
return BigInt(chainId * 2) + BigInt(35n + signature.v - 27n);
|
|
5191
|
+
// Pre-EIP-155 (no chainId)
|
|
5192
|
+
const v = 27n + (signature.v === 27n ? 0n : 1n);
|
|
5193
|
+
if (signature.v !== v)
|
|
5194
|
+
throw new InvalidLegacyVError({ v: signature.v });
|
|
5195
|
+
return v;
|
|
5196
|
+
})();
|
|
5197
|
+
serializedTransaction = [
|
|
5198
|
+
...serializedTransaction,
|
|
5199
|
+
toHex(v),
|
|
5200
|
+
signature.r,
|
|
5201
|
+
signature.s,
|
|
5202
|
+
];
|
|
5068
5203
|
}
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
}
|
|
5077
|
-
function encodeTuple(value, { param }) {
|
|
5078
|
-
let dynamic = false;
|
|
5079
|
-
const preparedParams = [];
|
|
5080
|
-
for (let i = 0; i < param.components.length; i++) {
|
|
5081
|
-
const param_ = param.components[i];
|
|
5082
|
-
const index = Array.isArray(value) ? i : param_.name;
|
|
5083
|
-
const preparedParam = prepareParam({
|
|
5084
|
-
param: param_,
|
|
5085
|
-
value: value[index],
|
|
5086
|
-
});
|
|
5087
|
-
preparedParams.push(preparedParam);
|
|
5088
|
-
if (preparedParam.dynamic)
|
|
5089
|
-
dynamic = true;
|
|
5204
|
+
else if (chainId > 0) {
|
|
5205
|
+
serializedTransaction = [
|
|
5206
|
+
...serializedTransaction,
|
|
5207
|
+
toHex(chainId),
|
|
5208
|
+
'0x',
|
|
5209
|
+
'0x',
|
|
5210
|
+
];
|
|
5090
5211
|
}
|
|
5091
|
-
return
|
|
5092
|
-
dynamic,
|
|
5093
|
-
encoded: dynamic
|
|
5094
|
-
? encodeParams(preparedParams)
|
|
5095
|
-
: concat(preparedParams.map(({ encoded }) => encoded)),
|
|
5096
|
-
};
|
|
5212
|
+
return toRlp(serializedTransaction);
|
|
5097
5213
|
}
|
|
5098
|
-
function
|
|
5099
|
-
const
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5214
|
+
function toYParitySignatureArray(transaction, signature_) {
|
|
5215
|
+
const signature = signature_ ?? transaction;
|
|
5216
|
+
const { v, yParity } = signature;
|
|
5217
|
+
if (typeof signature.r === 'undefined')
|
|
5218
|
+
return [];
|
|
5219
|
+
if (typeof signature.s === 'undefined')
|
|
5220
|
+
return [];
|
|
5221
|
+
if (typeof v === 'undefined' && typeof yParity === 'undefined')
|
|
5222
|
+
return [];
|
|
5223
|
+
const r = trim(signature.r);
|
|
5224
|
+
const s = trim(signature.s);
|
|
5225
|
+
const yParity_ = (() => {
|
|
5226
|
+
if (typeof yParity === 'number')
|
|
5227
|
+
return yParity ? toHex(1) : '0x';
|
|
5228
|
+
if (v === 0n)
|
|
5229
|
+
return '0x';
|
|
5230
|
+
if (v === 1n)
|
|
5231
|
+
return toHex(1);
|
|
5232
|
+
return v === 27n ? '0x' : toHex(1);
|
|
5233
|
+
})();
|
|
5234
|
+
return [yParity_, r === '0x00' ? '0x' : r, s === '0x00' ? '0x' : s];
|
|
5104
5235
|
}
|
|
5105
5236
|
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5237
|
+
async function signTransaction(parameters) {
|
|
5238
|
+
const { privateKey, transaction, serializer = serializeTransaction, } = parameters;
|
|
5239
|
+
const signableTransaction = (() => {
|
|
5240
|
+
// For EIP-4844 Transactions, we want to sign the transaction payload body (tx_payload_body) without the sidecars (ie. without the network wrapper).
|
|
5241
|
+
// See: https://github.com/ethereum/EIPs/blob/e00f4daa66bd56e2dbd5f1d36d09fd613811a48b/EIPS/eip-4844.md#networking
|
|
5242
|
+
if (transaction.type === 'eip4844')
|
|
5243
|
+
return {
|
|
5244
|
+
...transaction,
|
|
5245
|
+
sidecars: false,
|
|
5246
|
+
};
|
|
5247
|
+
return transaction;
|
|
5248
|
+
})();
|
|
5249
|
+
const signature = await sign({
|
|
5250
|
+
hash: keccak256(serializer(signableTransaction)),
|
|
5251
|
+
privateKey,
|
|
5252
|
+
});
|
|
5253
|
+
return serializer(transaction, signature);
|
|
5254
|
+
}
|
|
5255
|
+
|
|
5256
|
+
class AbiEncodingArrayLengthMismatchError extends BaseError {
|
|
5257
|
+
constructor({ expectedLength, givenLength, type, }) {
|
|
5258
|
+
super([
|
|
5259
|
+
`ABI encoding array length mismatch for type ${type}.`,
|
|
5260
|
+
`Expected length: ${expectedLength}`,
|
|
5261
|
+
`Given length: ${givenLength}`,
|
|
5262
|
+
].join('\n'));
|
|
5111
5263
|
Object.defineProperty(this, "name", {
|
|
5112
5264
|
enumerable: true,
|
|
5113
5265
|
configurable: true,
|
|
5114
5266
|
writable: true,
|
|
5115
|
-
value: '
|
|
5267
|
+
value: 'AbiEncodingArrayLengthMismatchError'
|
|
5116
5268
|
});
|
|
5117
5269
|
}
|
|
5118
5270
|
}
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
writable: true,
|
|
5123
|
-
value: /max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/
|
|
5124
|
-
});
|
|
5125
|
-
class TipAboveFeeCapError extends BaseError {
|
|
5126
|
-
constructor({ cause, maxPriorityFeePerGas, maxFeePerGas, } = {}) {
|
|
5127
|
-
super([
|
|
5128
|
-
`The provided tip (\`maxPriorityFeePerGas\`${maxPriorityFeePerGas
|
|
5129
|
-
? ` = ${formatGwei(maxPriorityFeePerGas)} gwei`
|
|
5130
|
-
: ''}) cannot be higher than the fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei(maxFeePerGas)} gwei` : ''}).`,
|
|
5131
|
-
].join('\n'), {
|
|
5132
|
-
cause,
|
|
5133
|
-
});
|
|
5271
|
+
class AbiEncodingBytesSizeMismatchError extends BaseError {
|
|
5272
|
+
constructor({ expectedSize, value }) {
|
|
5273
|
+
super(`Size of bytes "${value}" (bytes${size(value)}) does not match expected size (bytes${expectedSize}).`);
|
|
5134
5274
|
Object.defineProperty(this, "name", {
|
|
5135
5275
|
enumerable: true,
|
|
5136
5276
|
configurable: true,
|
|
5137
5277
|
writable: true,
|
|
5138
|
-
value: '
|
|
5278
|
+
value: 'AbiEncodingBytesSizeMismatchError'
|
|
5139
5279
|
});
|
|
5140
5280
|
}
|
|
5141
5281
|
}
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
}
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
typeof transaction.sidecars !== 'undefined')
|
|
5156
|
-
return 'eip4844';
|
|
5157
|
-
if (typeof transaction.maxFeePerGas !== 'undefined' ||
|
|
5158
|
-
typeof transaction.maxPriorityFeePerGas !== 'undefined') {
|
|
5159
|
-
return 'eip1559';
|
|
5160
|
-
}
|
|
5161
|
-
if (typeof transaction.gasPrice !== 'undefined') {
|
|
5162
|
-
if (typeof transaction.accessList !== 'undefined')
|
|
5163
|
-
return 'eip2930';
|
|
5164
|
-
return 'legacy';
|
|
5282
|
+
class AbiEncodingLengthMismatchError extends BaseError {
|
|
5283
|
+
constructor({ expectedLength, givenLength, }) {
|
|
5284
|
+
super([
|
|
5285
|
+
'ABI encoding params/values length mismatch.',
|
|
5286
|
+
`Expected length (params): ${expectedLength}`,
|
|
5287
|
+
`Given length (values): ${givenLength}`,
|
|
5288
|
+
].join('\n'));
|
|
5289
|
+
Object.defineProperty(this, "name", {
|
|
5290
|
+
enumerable: true,
|
|
5291
|
+
configurable: true,
|
|
5292
|
+
writable: true,
|
|
5293
|
+
value: 'AbiEncodingLengthMismatchError'
|
|
5294
|
+
});
|
|
5165
5295
|
}
|
|
5166
|
-
throw new InvalidSerializableTransactionError({ transaction });
|
|
5167
5296
|
}
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
super(typeof chainId === 'number'
|
|
5172
|
-
? `Chain ID "${chainId}" is invalid.`
|
|
5173
|
-
: 'Chain ID is invalid.');
|
|
5297
|
+
class BytesSizeMismatchError extends BaseError {
|
|
5298
|
+
constructor({ expectedSize, givenSize, }) {
|
|
5299
|
+
super(`Expected bytes${expectedSize}, got bytes${givenSize}.`);
|
|
5174
5300
|
Object.defineProperty(this, "name", {
|
|
5175
5301
|
enumerable: true,
|
|
5176
5302
|
configurable: true,
|
|
5177
5303
|
writable: true,
|
|
5178
|
-
value: '
|
|
5304
|
+
value: 'BytesSizeMismatchError'
|
|
5179
5305
|
});
|
|
5180
5306
|
}
|
|
5181
5307
|
}
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
...parameters.types,
|
|
5196
|
-
};
|
|
5197
|
-
// Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc
|
|
5198
|
-
// as we can't statically check this with TypeScript.
|
|
5199
|
-
validateTypedData({
|
|
5200
|
-
domain,
|
|
5201
|
-
message,
|
|
5202
|
-
primaryType,
|
|
5203
|
-
types,
|
|
5204
|
-
});
|
|
5205
|
-
const parts = ['0x1901'];
|
|
5206
|
-
if (domain)
|
|
5207
|
-
parts.push(hashDomain({
|
|
5208
|
-
domain,
|
|
5209
|
-
types: types,
|
|
5210
|
-
}));
|
|
5211
|
-
if (primaryType !== 'EIP712Domain')
|
|
5212
|
-
parts.push(hashStruct({
|
|
5213
|
-
data: message,
|
|
5214
|
-
primaryType,
|
|
5215
|
-
types: types,
|
|
5216
|
-
}));
|
|
5217
|
-
return keccak256(concat(parts));
|
|
5218
|
-
}
|
|
5219
|
-
function hashDomain({ domain, types, }) {
|
|
5220
|
-
return hashStruct({
|
|
5221
|
-
data: domain,
|
|
5222
|
-
primaryType: 'EIP712Domain',
|
|
5223
|
-
types,
|
|
5224
|
-
});
|
|
5225
|
-
}
|
|
5226
|
-
function hashStruct({ data, primaryType, types, }) {
|
|
5227
|
-
const encoded = encodeData({
|
|
5228
|
-
data,
|
|
5229
|
-
primaryType,
|
|
5230
|
-
types,
|
|
5231
|
-
});
|
|
5232
|
-
return keccak256(encoded);
|
|
5308
|
+
class InvalidAbiEncodingTypeError extends BaseError {
|
|
5309
|
+
constructor(type, { docsPath }) {
|
|
5310
|
+
super([
|
|
5311
|
+
`Type "${type}" is not a valid encoding type.`,
|
|
5312
|
+
'Please provide a valid ABI type.',
|
|
5313
|
+
].join('\n'), { docsPath });
|
|
5314
|
+
Object.defineProperty(this, "name", {
|
|
5315
|
+
enumerable: true,
|
|
5316
|
+
configurable: true,
|
|
5317
|
+
writable: true,
|
|
5318
|
+
value: 'InvalidAbiEncodingType'
|
|
5319
|
+
});
|
|
5320
|
+
}
|
|
5233
5321
|
}
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
value: data[field.name],
|
|
5322
|
+
class InvalidArrayError extends BaseError {
|
|
5323
|
+
constructor(value) {
|
|
5324
|
+
super([`Value "${value}" is not a valid array.`].join('\n'));
|
|
5325
|
+
Object.defineProperty(this, "name", {
|
|
5326
|
+
enumerable: true,
|
|
5327
|
+
configurable: true,
|
|
5328
|
+
writable: true,
|
|
5329
|
+
value: 'InvalidArrayError'
|
|
5243
5330
|
});
|
|
5244
|
-
encodedTypes.push(type);
|
|
5245
|
-
encodedValues.push(value);
|
|
5246
5331
|
}
|
|
5247
|
-
return encodeAbiParameters(encodedTypes, encodedValues);
|
|
5248
5332
|
}
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5333
|
+
|
|
5334
|
+
/**
|
|
5335
|
+
* @description Encodes a list of primitive values into an ABI-encoded hex value.
|
|
5336
|
+
*
|
|
5337
|
+
* - Docs: https://viem.sh/docs/abi/encodeAbiParameters#encodeabiparameters
|
|
5338
|
+
*
|
|
5339
|
+
* Generates ABI encoded data using the [ABI specification](https://docs.soliditylang.org/en/latest/abi-spec), given a set of ABI parameters (inputs/outputs) and their corresponding values.
|
|
5340
|
+
*
|
|
5341
|
+
* @param params - a set of ABI Parameters (params), that can be in the shape of the inputs or outputs attribute of an ABI Item.
|
|
5342
|
+
* @param values - a set of values (values) that correspond to the given params.
|
|
5343
|
+
* @example
|
|
5344
|
+
* ```typescript
|
|
5345
|
+
* import { encodeAbiParameters } from 'viem'
|
|
5346
|
+
*
|
|
5347
|
+
* const encodedData = encodeAbiParameters(
|
|
5348
|
+
* [
|
|
5349
|
+
* { name: 'x', type: 'string' },
|
|
5350
|
+
* { name: 'y', type: 'uint' },
|
|
5351
|
+
* { name: 'z', type: 'bool' }
|
|
5352
|
+
* ],
|
|
5353
|
+
* ['wagmi', 420n, true]
|
|
5354
|
+
* )
|
|
5355
|
+
* ```
|
|
5356
|
+
*
|
|
5357
|
+
* You can also pass in Human Readable parameters with the parseAbiParameters utility.
|
|
5358
|
+
*
|
|
5359
|
+
* @example
|
|
5360
|
+
* ```typescript
|
|
5361
|
+
* import { encodeAbiParameters, parseAbiParameters } from 'viem'
|
|
5362
|
+
*
|
|
5363
|
+
* const encodedData = encodeAbiParameters(
|
|
5364
|
+
* parseAbiParameters('string x, uint y, bool z'),
|
|
5365
|
+
* ['wagmi', 420n, true]
|
|
5366
|
+
* )
|
|
5367
|
+
* ```
|
|
5368
|
+
*/
|
|
5369
|
+
function encodeAbiParameters(params, values) {
|
|
5370
|
+
if (params.length !== values.length)
|
|
5371
|
+
throw new AbiEncodingLengthMismatchError({
|
|
5372
|
+
expectedLength: params.length,
|
|
5373
|
+
givenLength: values.length,
|
|
5374
|
+
});
|
|
5375
|
+
// Prepare the parameters to determine dynamic types to encode.
|
|
5376
|
+
const preparedParams = prepareParams({
|
|
5377
|
+
params: params,
|
|
5378
|
+
values: values,
|
|
5379
|
+
});
|
|
5380
|
+
const data = encodeParams(preparedParams);
|
|
5381
|
+
if (data.length === 0)
|
|
5382
|
+
return '0x';
|
|
5383
|
+
return data;
|
|
5252
5384
|
}
|
|
5253
|
-
function
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
const deps = [primaryType, ...Array.from(unsortedDeps).sort()];
|
|
5258
|
-
for (const type of deps) {
|
|
5259
|
-
result += `${type}(${types[type]
|
|
5260
|
-
.map(({ name, type: t }) => `${t} ${name}`)
|
|
5261
|
-
.join(',')})`;
|
|
5385
|
+
function prepareParams({ params, values, }) {
|
|
5386
|
+
const preparedParams = [];
|
|
5387
|
+
for (let i = 0; i < params.length; i++) {
|
|
5388
|
+
preparedParams.push(prepareParam({ param: params[i], value: values[i] }));
|
|
5262
5389
|
}
|
|
5263
|
-
return
|
|
5390
|
+
return preparedParams;
|
|
5264
5391
|
}
|
|
5265
|
-
function
|
|
5266
|
-
const
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
return
|
|
5392
|
+
function prepareParam({ param, value, }) {
|
|
5393
|
+
const arrayComponents = getArrayComponents(param.type);
|
|
5394
|
+
if (arrayComponents) {
|
|
5395
|
+
const [length, type] = arrayComponents;
|
|
5396
|
+
return encodeArray(value, { length, param: { ...param, type } });
|
|
5270
5397
|
}
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5398
|
+
if (param.type === 'tuple') {
|
|
5399
|
+
return encodeTuple(value, {
|
|
5400
|
+
param: param,
|
|
5401
|
+
});
|
|
5274
5402
|
}
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
function encodeField({ types, name, type, value, }) {
|
|
5278
|
-
if (types[type] !== undefined) {
|
|
5279
|
-
return [
|
|
5280
|
-
{ type: 'bytes32' },
|
|
5281
|
-
keccak256(encodeData({ data: value, primaryType: type, types })),
|
|
5282
|
-
];
|
|
5403
|
+
if (param.type === 'address') {
|
|
5404
|
+
return encodeAddress(value);
|
|
5283
5405
|
}
|
|
5284
|
-
if (type === '
|
|
5285
|
-
|
|
5286
|
-
value = `0x${prepend + value.slice(2)}`;
|
|
5287
|
-
return [{ type: 'bytes32' }, keccak256(value)];
|
|
5406
|
+
if (param.type === 'bool') {
|
|
5407
|
+
return encodeBool(value);
|
|
5288
5408
|
}
|
|
5289
|
-
if (type
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
const parsedType = type.slice(0, type.lastIndexOf('['));
|
|
5293
|
-
const typeValuePairs = value.map((item) => encodeField({
|
|
5294
|
-
name,
|
|
5295
|
-
type: parsedType,
|
|
5296
|
-
types,
|
|
5297
|
-
value: item,
|
|
5298
|
-
}));
|
|
5299
|
-
return [
|
|
5300
|
-
{ type: 'bytes32' },
|
|
5301
|
-
keccak256(encodeAbiParameters(typeValuePairs.map(([t]) => t), typeValuePairs.map(([, v]) => v))),
|
|
5302
|
-
];
|
|
5409
|
+
if (param.type.startsWith('uint') || param.type.startsWith('int')) {
|
|
5410
|
+
const signed = param.type.startsWith('int');
|
|
5411
|
+
return encodeNumber(value, { signed });
|
|
5303
5412
|
}
|
|
5304
|
-
|
|
5305
|
-
}
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
const validateData = (struct, data) => {
|
|
5310
|
-
for (const param of struct) {
|
|
5311
|
-
const { name, type } = param;
|
|
5312
|
-
const value = data[name];
|
|
5313
|
-
const integerMatch = type.match(integerRegex);
|
|
5314
|
-
if (integerMatch &&
|
|
5315
|
-
(typeof value === 'number' || typeof value === 'bigint')) {
|
|
5316
|
-
const [_type, base, size_] = integerMatch;
|
|
5317
|
-
// If number cannot be cast to a sized hex value, it is out of range
|
|
5318
|
-
// and will throw.
|
|
5319
|
-
numberToHex(value, {
|
|
5320
|
-
signed: base === 'int',
|
|
5321
|
-
size: parseInt(size_) / 8,
|
|
5322
|
-
});
|
|
5323
|
-
}
|
|
5324
|
-
if (type === 'address' && typeof value === 'string' && !isAddress(value))
|
|
5325
|
-
throw new InvalidAddressError({ address: value });
|
|
5326
|
-
const bytesMatch = type.match(bytesRegex);
|
|
5327
|
-
if (bytesMatch) {
|
|
5328
|
-
const [_type, size_] = bytesMatch;
|
|
5329
|
-
if (size_ && size(value) !== parseInt(size_))
|
|
5330
|
-
throw new BytesSizeMismatchError({
|
|
5331
|
-
expectedSize: parseInt(size_),
|
|
5332
|
-
givenSize: size(value),
|
|
5333
|
-
});
|
|
5334
|
-
}
|
|
5335
|
-
const struct = types[type];
|
|
5336
|
-
if (struct)
|
|
5337
|
-
validateData(struct, value);
|
|
5338
|
-
}
|
|
5339
|
-
};
|
|
5340
|
-
// Validate domain types.
|
|
5341
|
-
if (types.EIP712Domain && domain)
|
|
5342
|
-
validateData(types.EIP712Domain, domain);
|
|
5343
|
-
if (primaryType !== 'EIP712Domain') {
|
|
5344
|
-
// Validate message types.
|
|
5345
|
-
const type = types[primaryType];
|
|
5346
|
-
validateData(type, message);
|
|
5413
|
+
if (param.type.startsWith('bytes')) {
|
|
5414
|
+
return encodeBytes(value, { param });
|
|
5415
|
+
}
|
|
5416
|
+
if (param.type === 'string') {
|
|
5417
|
+
return encodeString(value);
|
|
5347
5418
|
}
|
|
5419
|
+
throw new InvalidAbiEncodingTypeError(param.type, {
|
|
5420
|
+
docsPath: '/docs/contract/encodeAbiParameters',
|
|
5421
|
+
});
|
|
5348
5422
|
}
|
|
5349
|
-
function
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
const version = hexToNumber(slice(hash, 0, 1));
|
|
5373
|
-
if (size_ !== 32)
|
|
5374
|
-
throw new InvalidVersionedHashSizeError({ hash, size: size_ });
|
|
5375
|
-
if (version !== versionedHashVersionKzg)
|
|
5376
|
-
throw new InvalidVersionedHashVersionError({
|
|
5377
|
-
hash,
|
|
5378
|
-
version,
|
|
5379
|
-
});
|
|
5423
|
+
function encodeParams(preparedParams) {
|
|
5424
|
+
// 1. Compute the size of the static part of the parameters.
|
|
5425
|
+
let staticSize = 0;
|
|
5426
|
+
for (let i = 0; i < preparedParams.length; i++) {
|
|
5427
|
+
const { dynamic, encoded } = preparedParams[i];
|
|
5428
|
+
if (dynamic)
|
|
5429
|
+
staticSize += 32;
|
|
5430
|
+
else
|
|
5431
|
+
staticSize += size(encoded);
|
|
5432
|
+
}
|
|
5433
|
+
// 2. Split the parameters into static and dynamic parts.
|
|
5434
|
+
const staticParams = [];
|
|
5435
|
+
const dynamicParams = [];
|
|
5436
|
+
let dynamicSize = 0;
|
|
5437
|
+
for (let i = 0; i < preparedParams.length; i++) {
|
|
5438
|
+
const { dynamic, encoded } = preparedParams[i];
|
|
5439
|
+
if (dynamic) {
|
|
5440
|
+
staticParams.push(numberToHex(staticSize + dynamicSize, { size: 32 }));
|
|
5441
|
+
dynamicParams.push(encoded);
|
|
5442
|
+
dynamicSize += size(encoded);
|
|
5443
|
+
}
|
|
5444
|
+
else {
|
|
5445
|
+
staticParams.push(encoded);
|
|
5380
5446
|
}
|
|
5381
5447
|
}
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
function assertTransactionEIP1559(transaction) {
|
|
5385
|
-
const { chainId, maxPriorityFeePerGas, maxFeePerGas, to } = transaction;
|
|
5386
|
-
if (chainId <= 0)
|
|
5387
|
-
throw new InvalidChainIdError({ chainId });
|
|
5388
|
-
if (to && !isAddress(to))
|
|
5389
|
-
throw new InvalidAddressError({ address: to });
|
|
5390
|
-
if (maxFeePerGas && maxFeePerGas > 2n ** 256n - 1n)
|
|
5391
|
-
throw new FeeCapTooHighError({ maxFeePerGas });
|
|
5392
|
-
if (maxPriorityFeePerGas &&
|
|
5393
|
-
maxFeePerGas &&
|
|
5394
|
-
maxPriorityFeePerGas > maxFeePerGas)
|
|
5395
|
-
throw new TipAboveFeeCapError({ maxFeePerGas, maxPriorityFeePerGas });
|
|
5396
|
-
}
|
|
5397
|
-
function assertTransactionEIP2930(transaction) {
|
|
5398
|
-
const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to } = transaction;
|
|
5399
|
-
if (chainId <= 0)
|
|
5400
|
-
throw new InvalidChainIdError({ chainId });
|
|
5401
|
-
if (to && !isAddress(to))
|
|
5402
|
-
throw new InvalidAddressError({ address: to });
|
|
5403
|
-
if (maxPriorityFeePerGas || maxFeePerGas)
|
|
5404
|
-
throw new BaseError('`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid EIP-2930 Transaction attribute.');
|
|
5405
|
-
if (gasPrice && gasPrice > 2n ** 256n - 1n)
|
|
5406
|
-
throw new FeeCapTooHighError({ maxFeePerGas: gasPrice });
|
|
5448
|
+
// 3. Concatenate static and dynamic parts.
|
|
5449
|
+
return concat([...staticParams, ...dynamicParams]);
|
|
5407
5450
|
}
|
|
5408
|
-
function
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
if (typeof chainId !== 'undefined' && chainId <= 0)
|
|
5413
|
-
throw new InvalidChainIdError({ chainId });
|
|
5414
|
-
if (maxPriorityFeePerGas || maxFeePerGas)
|
|
5415
|
-
throw new BaseError('`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid Legacy Transaction attribute.');
|
|
5416
|
-
if (gasPrice && gasPrice > 2n ** 256n - 1n)
|
|
5417
|
-
throw new FeeCapTooHighError({ maxFeePerGas: gasPrice });
|
|
5418
|
-
if (accessList)
|
|
5419
|
-
throw new BaseError('`accessList` is not a valid Legacy Transaction attribute.');
|
|
5451
|
+
function encodeAddress(value) {
|
|
5452
|
+
if (!isAddress(value))
|
|
5453
|
+
throw new InvalidAddressError({ address: value });
|
|
5454
|
+
return { dynamic: false, encoded: padHex(value.toLowerCase()) };
|
|
5420
5455
|
}
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5456
|
+
function encodeArray(value, { length, param, }) {
|
|
5457
|
+
const dynamic = length === null;
|
|
5458
|
+
if (!Array.isArray(value))
|
|
5459
|
+
throw new InvalidArrayError(value);
|
|
5460
|
+
if (!dynamic && value.length !== length)
|
|
5461
|
+
throw new AbiEncodingArrayLengthMismatchError({
|
|
5462
|
+
expectedLength: length,
|
|
5463
|
+
givenLength: value.length,
|
|
5464
|
+
type: `${param.type}[${length}]`,
|
|
5465
|
+
});
|
|
5466
|
+
let dynamicChild = false;
|
|
5467
|
+
const preparedParams = [];
|
|
5468
|
+
for (let i = 0; i < value.length; i++) {
|
|
5469
|
+
const preparedParam = prepareParam({ param, value: value[i] });
|
|
5470
|
+
if (preparedParam.dynamic)
|
|
5471
|
+
dynamicChild = true;
|
|
5472
|
+
preparedParams.push(preparedParam);
|
|
5473
|
+
}
|
|
5474
|
+
if (dynamic || dynamicChild) {
|
|
5475
|
+
const data = encodeParams(preparedParams);
|
|
5476
|
+
if (dynamic) {
|
|
5477
|
+
const length = numberToHex(preparedParams.length, { size: 32 });
|
|
5478
|
+
return {
|
|
5479
|
+
dynamic: true,
|
|
5480
|
+
encoded: preparedParams.length > 0 ? concat([length, data]) : length,
|
|
5481
|
+
};
|
|
5444
5482
|
}
|
|
5445
|
-
|
|
5483
|
+
if (dynamicChild)
|
|
5484
|
+
return { dynamic: true, encoded: data };
|
|
5446
5485
|
}
|
|
5447
|
-
return
|
|
5486
|
+
return {
|
|
5487
|
+
dynamic: false,
|
|
5488
|
+
encoded: concat(preparedParams.map(({ encoded }) => encoded)),
|
|
5489
|
+
};
|
|
5448
5490
|
}
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
const
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5491
|
+
function encodeBytes(value, { param }) {
|
|
5492
|
+
const [, paramSize] = param.type.split('bytes');
|
|
5493
|
+
const bytesSize = size(value);
|
|
5494
|
+
if (!paramSize) {
|
|
5495
|
+
let value_ = value;
|
|
5496
|
+
// If the size is not divisible by 32 bytes, pad the end
|
|
5497
|
+
// with empty bytes to the ceiling 32 bytes.
|
|
5498
|
+
if (bytesSize % 32 !== 0)
|
|
5499
|
+
value_ = padHex(value_, {
|
|
5500
|
+
dir: 'right',
|
|
5501
|
+
size: Math.ceil((value.length - 2) / 2 / 32) * 32,
|
|
5502
|
+
});
|
|
5503
|
+
return {
|
|
5504
|
+
dynamic: true,
|
|
5505
|
+
encoded: concat([padHex(numberToHex(bytesSize, { size: 32 })), value_]),
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
5508
|
+
if (bytesSize !== Number.parseInt(paramSize))
|
|
5509
|
+
throw new AbiEncodingBytesSizeMismatchError({
|
|
5510
|
+
expectedSize: Number.parseInt(paramSize),
|
|
5511
|
+
value,
|
|
5512
|
+
});
|
|
5513
|
+
return { dynamic: false, encoded: padHex(value, { dir: 'right' }) };
|
|
5457
5514
|
}
|
|
5458
|
-
function
|
|
5459
|
-
if (
|
|
5460
|
-
|
|
5461
|
-
return
|
|
5515
|
+
function encodeBool(value) {
|
|
5516
|
+
if (typeof value !== 'boolean')
|
|
5517
|
+
throw new BaseError(`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`);
|
|
5518
|
+
return { dynamic: false, encoded: padHex(boolToHex(value)) };
|
|
5462
5519
|
}
|
|
5463
|
-
function
|
|
5464
|
-
const bodyLength = list.reduce((acc, x) => acc + x.length, 0);
|
|
5465
|
-
const sizeOfBodyLength = getSizeOfLength(bodyLength);
|
|
5466
|
-
const length = (() => {
|
|
5467
|
-
if (bodyLength <= 55)
|
|
5468
|
-
return 1 + bodyLength;
|
|
5469
|
-
return 1 + sizeOfBodyLength + bodyLength;
|
|
5470
|
-
})();
|
|
5520
|
+
function encodeNumber(value, { signed }) {
|
|
5471
5521
|
return {
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
else {
|
|
5478
|
-
cursor.pushByte(0xc0 + 55 + sizeOfBodyLength);
|
|
5479
|
-
if (sizeOfBodyLength === 1)
|
|
5480
|
-
cursor.pushUint8(bodyLength);
|
|
5481
|
-
else if (sizeOfBodyLength === 2)
|
|
5482
|
-
cursor.pushUint16(bodyLength);
|
|
5483
|
-
else if (sizeOfBodyLength === 3)
|
|
5484
|
-
cursor.pushUint24(bodyLength);
|
|
5485
|
-
else
|
|
5486
|
-
cursor.pushUint32(bodyLength);
|
|
5487
|
-
}
|
|
5488
|
-
for (const { encode } of list) {
|
|
5489
|
-
encode(cursor);
|
|
5490
|
-
}
|
|
5491
|
-
},
|
|
5522
|
+
dynamic: false,
|
|
5523
|
+
encoded: numberToHex(value, {
|
|
5524
|
+
size: 32,
|
|
5525
|
+
signed,
|
|
5526
|
+
}),
|
|
5492
5527
|
};
|
|
5493
5528
|
}
|
|
5494
|
-
function
|
|
5495
|
-
const
|
|
5496
|
-
const
|
|
5497
|
-
const
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
})();
|
|
5529
|
+
function encodeString(value) {
|
|
5530
|
+
const hexValue = stringToHex(value);
|
|
5531
|
+
const partsLength = Math.ceil(size(hexValue) / 32);
|
|
5532
|
+
const parts = [];
|
|
5533
|
+
for (let i = 0; i < partsLength; i++) {
|
|
5534
|
+
parts.push(padHex(slice(hexValue, i * 32, (i + 1) * 32), {
|
|
5535
|
+
dir: 'right',
|
|
5536
|
+
}));
|
|
5537
|
+
}
|
|
5504
5538
|
return {
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
cursor.pushByte(0x80 + bytes.length);
|
|
5512
|
-
cursor.pushBytes(bytes);
|
|
5513
|
-
}
|
|
5514
|
-
else {
|
|
5515
|
-
cursor.pushByte(0x80 + 55 + sizeOfBytesLength);
|
|
5516
|
-
if (sizeOfBytesLength === 1)
|
|
5517
|
-
cursor.pushUint8(bytes.length);
|
|
5518
|
-
else if (sizeOfBytesLength === 2)
|
|
5519
|
-
cursor.pushUint16(bytes.length);
|
|
5520
|
-
else if (sizeOfBytesLength === 3)
|
|
5521
|
-
cursor.pushUint24(bytes.length);
|
|
5522
|
-
else
|
|
5523
|
-
cursor.pushUint32(bytes.length);
|
|
5524
|
-
cursor.pushBytes(bytes);
|
|
5525
|
-
}
|
|
5526
|
-
},
|
|
5527
|
-
};
|
|
5539
|
+
dynamic: true,
|
|
5540
|
+
encoded: concat([
|
|
5541
|
+
padHex(numberToHex(size(hexValue), { size: 32 })),
|
|
5542
|
+
...parts,
|
|
5543
|
+
]),
|
|
5544
|
+
};
|
|
5528
5545
|
}
|
|
5529
|
-
function
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5546
|
+
function encodeTuple(value, { param }) {
|
|
5547
|
+
let dynamic = false;
|
|
5548
|
+
const preparedParams = [];
|
|
5549
|
+
for (let i = 0; i < param.components.length; i++) {
|
|
5550
|
+
const param_ = param.components[i];
|
|
5551
|
+
const index = Array.isArray(value) ? i : param_.name;
|
|
5552
|
+
const preparedParam = prepareParam({
|
|
5553
|
+
param: param_,
|
|
5554
|
+
value: value[index],
|
|
5555
|
+
});
|
|
5556
|
+
preparedParams.push(preparedParam);
|
|
5557
|
+
if (preparedParam.dynamic)
|
|
5558
|
+
dynamic = true;
|
|
5559
|
+
}
|
|
5560
|
+
return {
|
|
5561
|
+
dynamic,
|
|
5562
|
+
encoded: dynamic
|
|
5563
|
+
? encodeParams(preparedParams)
|
|
5564
|
+
: concat(preparedParams.map(({ encoded }) => encoded)),
|
|
5565
|
+
};
|
|
5566
|
+
}
|
|
5567
|
+
function getArrayComponents(type) {
|
|
5568
|
+
const matches = type.match(/^(.*)\[(\d+)?\]$/);
|
|
5569
|
+
return matches
|
|
5570
|
+
? // Return `null` if the array is dynamic.
|
|
5571
|
+
[matches[2] ? Number(matches[2]) : null, matches[1]]
|
|
5572
|
+
: undefined;
|
|
5539
5573
|
}
|
|
5540
5574
|
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5575
|
+
// `bytes<M>`: binary type of `M` bytes, `0 < M <= 32`
|
|
5576
|
+
// https://regexr.com/6va55
|
|
5577
|
+
const bytesRegex = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/;
|
|
5578
|
+
// `(u)int<M>`: (un)signed integer type of `M` bits, `0 < M <= 256`, `M % 8 == 0`
|
|
5579
|
+
// https://regexr.com/6v8hp
|
|
5580
|
+
const integerRegex = /^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;
|
|
5581
|
+
|
|
5582
|
+
function validateTypedData(parameters) {
|
|
5583
|
+
const { domain, message, primaryType, types } = parameters;
|
|
5584
|
+
const validateData = (struct, data) => {
|
|
5585
|
+
for (const param of struct) {
|
|
5586
|
+
const { name, type } = param;
|
|
5587
|
+
const value = data[name];
|
|
5588
|
+
const integerMatch = type.match(integerRegex);
|
|
5589
|
+
if (integerMatch &&
|
|
5590
|
+
(typeof value === 'number' || typeof value === 'bigint')) {
|
|
5591
|
+
const [_type, base, size_] = integerMatch;
|
|
5592
|
+
// If number cannot be cast to a sized hex value, it is out of range
|
|
5593
|
+
// and will throw.
|
|
5594
|
+
numberToHex(value, {
|
|
5595
|
+
signed: base === 'int',
|
|
5596
|
+
size: Number.parseInt(size_) / 8,
|
|
5597
|
+
});
|
|
5598
|
+
}
|
|
5599
|
+
if (type === 'address' && typeof value === 'string' && !isAddress(value))
|
|
5600
|
+
throw new InvalidAddressError({ address: value });
|
|
5601
|
+
const bytesMatch = type.match(bytesRegex);
|
|
5602
|
+
if (bytesMatch) {
|
|
5603
|
+
const [_type, size_] = bytesMatch;
|
|
5604
|
+
if (size_ && size(value) !== Number.parseInt(size_))
|
|
5605
|
+
throw new BytesSizeMismatchError({
|
|
5606
|
+
expectedSize: Number.parseInt(size_),
|
|
5607
|
+
givenSize: size(value),
|
|
5608
|
+
});
|
|
5609
|
+
}
|
|
5610
|
+
const struct = types[type];
|
|
5611
|
+
if (struct)
|
|
5612
|
+
validateData(struct, value);
|
|
5613
|
+
}
|
|
5614
|
+
};
|
|
5615
|
+
// Validate domain types.
|
|
5616
|
+
if (types.EIP712Domain && domain)
|
|
5617
|
+
validateData(types.EIP712Domain, domain);
|
|
5618
|
+
// Validate message types.
|
|
5619
|
+
if (primaryType !== 'EIP712Domain')
|
|
5620
|
+
validateData(types[primaryType], message);
|
|
5550
5621
|
}
|
|
5551
|
-
function
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5622
|
+
function getTypesForEIP712Domain({ domain, }) {
|
|
5623
|
+
return [
|
|
5624
|
+
typeof domain?.name === 'string' && { name: 'name', type: 'string' },
|
|
5625
|
+
domain?.version && { name: 'version', type: 'string' },
|
|
5626
|
+
typeof domain?.chainId === 'number' && {
|
|
5627
|
+
name: 'chainId',
|
|
5628
|
+
type: 'uint256',
|
|
5629
|
+
},
|
|
5630
|
+
domain?.verifyingContract && {
|
|
5631
|
+
name: 'verifyingContract',
|
|
5632
|
+
type: 'address',
|
|
5633
|
+
},
|
|
5634
|
+
domain?.salt && { name: 'salt', type: 'bytes32' },
|
|
5635
|
+
].filter(Boolean);
|
|
5636
|
+
}
|
|
5637
|
+
|
|
5638
|
+
// Implementation forked and adapted from https://github.com/MetaMask/eth-sig-util/blob/main/src/sign-typed-data.ts
|
|
5639
|
+
function hashTypedData(parameters) {
|
|
5640
|
+
const { domain = {}, message, primaryType, } = parameters;
|
|
5641
|
+
const types = {
|
|
5642
|
+
EIP712Domain: getTypesForEIP712Domain({ domain }),
|
|
5643
|
+
...parameters.types,
|
|
5644
|
+
};
|
|
5645
|
+
// Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc
|
|
5646
|
+
// as we can't statically check this with TypeScript.
|
|
5647
|
+
validateTypedData({
|
|
5648
|
+
domain,
|
|
5649
|
+
message,
|
|
5650
|
+
primaryType,
|
|
5651
|
+
types,
|
|
5652
|
+
});
|
|
5653
|
+
const parts = ['0x1901'];
|
|
5654
|
+
if (domain)
|
|
5655
|
+
parts.push(hashDomain({
|
|
5656
|
+
domain,
|
|
5657
|
+
types: types,
|
|
5658
|
+
}));
|
|
5659
|
+
if (primaryType !== 'EIP712Domain')
|
|
5660
|
+
parts.push(hashStruct({
|
|
5661
|
+
data: message,
|
|
5662
|
+
primaryType,
|
|
5663
|
+
types: types,
|
|
5664
|
+
}));
|
|
5665
|
+
return keccak256(concat(parts));
|
|
5666
|
+
}
|
|
5667
|
+
function hashDomain({ domain, types, }) {
|
|
5668
|
+
return hashStruct({
|
|
5669
|
+
data: domain,
|
|
5670
|
+
primaryType: 'EIP712Domain',
|
|
5671
|
+
types,
|
|
5672
|
+
});
|
|
5673
|
+
}
|
|
5674
|
+
function hashStruct({ data, primaryType, types, }) {
|
|
5675
|
+
const encoded = encodeData({
|
|
5676
|
+
data,
|
|
5677
|
+
primaryType,
|
|
5678
|
+
types,
|
|
5679
|
+
});
|
|
5680
|
+
return keccak256(encoded);
|
|
5681
|
+
}
|
|
5682
|
+
function encodeData({ data, primaryType, types, }) {
|
|
5683
|
+
const encodedTypes = [{ type: 'bytes32' }];
|
|
5684
|
+
const encodedValues = [hashType({ primaryType, types })];
|
|
5685
|
+
for (const field of types[primaryType]) {
|
|
5686
|
+
const [type, value] = encodeField({
|
|
5687
|
+
types,
|
|
5688
|
+
name: field.name,
|
|
5689
|
+
type: field.type,
|
|
5690
|
+
value: data[field.name],
|
|
5567
5691
|
});
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
commitments,
|
|
5571
|
-
});
|
|
5572
|
-
if (typeof sidecars === 'undefined') {
|
|
5573
|
-
const proofs = blobsToProofs({ blobs, commitments, kzg });
|
|
5574
|
-
sidecars = toBlobSidecars({ blobs, commitments, proofs });
|
|
5575
|
-
}
|
|
5692
|
+
encodedTypes.push(type);
|
|
5693
|
+
encodedValues.push(value);
|
|
5576
5694
|
}
|
|
5577
|
-
|
|
5578
|
-
const serializedTransaction = [
|
|
5579
|
-
toHex(chainId),
|
|
5580
|
-
nonce ? toHex(nonce) : '0x',
|
|
5581
|
-
maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x',
|
|
5582
|
-
maxFeePerGas ? toHex(maxFeePerGas) : '0x',
|
|
5583
|
-
gas ? toHex(gas) : '0x',
|
|
5584
|
-
to ?? '0x',
|
|
5585
|
-
value ? toHex(value) : '0x',
|
|
5586
|
-
data ?? '0x',
|
|
5587
|
-
serializedAccessList,
|
|
5588
|
-
maxFeePerBlobGas ? toHex(maxFeePerBlobGas) : '0x',
|
|
5589
|
-
blobVersionedHashes ?? [],
|
|
5590
|
-
...toYParitySignatureArray(transaction, signature),
|
|
5591
|
-
];
|
|
5592
|
-
const blobs = [];
|
|
5593
|
-
const commitments = [];
|
|
5594
|
-
const proofs = [];
|
|
5595
|
-
if (sidecars)
|
|
5596
|
-
for (let i = 0; i < sidecars.length; i++) {
|
|
5597
|
-
const { blob, commitment, proof } = sidecars[i];
|
|
5598
|
-
blobs.push(blob);
|
|
5599
|
-
commitments.push(commitment);
|
|
5600
|
-
proofs.push(proof);
|
|
5601
|
-
}
|
|
5602
|
-
return concatHex([
|
|
5603
|
-
'0x03',
|
|
5604
|
-
sidecars
|
|
5605
|
-
? // If sidecars are enabled, envelope turns into a "wrapper":
|
|
5606
|
-
toRlp([serializedTransaction, blobs, commitments, proofs])
|
|
5607
|
-
: // If sidecars are disabled, standard envelope is used:
|
|
5608
|
-
toRlp(serializedTransaction),
|
|
5609
|
-
]);
|
|
5695
|
+
return encodeAbiParameters(encodedTypes, encodedValues);
|
|
5610
5696
|
}
|
|
5611
|
-
function
|
|
5612
|
-
const
|
|
5613
|
-
|
|
5614
|
-
const serializedAccessList = serializeAccessList(accessList);
|
|
5615
|
-
const serializedTransaction = [
|
|
5616
|
-
toHex(chainId),
|
|
5617
|
-
nonce ? toHex(nonce) : '0x',
|
|
5618
|
-
maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x',
|
|
5619
|
-
maxFeePerGas ? toHex(maxFeePerGas) : '0x',
|
|
5620
|
-
gas ? toHex(gas) : '0x',
|
|
5621
|
-
to ?? '0x',
|
|
5622
|
-
value ? toHex(value) : '0x',
|
|
5623
|
-
data ?? '0x',
|
|
5624
|
-
serializedAccessList,
|
|
5625
|
-
...toYParitySignatureArray(transaction, signature),
|
|
5626
|
-
];
|
|
5627
|
-
return concatHex([
|
|
5628
|
-
'0x02',
|
|
5629
|
-
toRlp(serializedTransaction),
|
|
5630
|
-
]);
|
|
5697
|
+
function hashType({ primaryType, types, }) {
|
|
5698
|
+
const encodedHashType = toHex(encodeType({ primaryType, types }));
|
|
5699
|
+
return keccak256(encodedHashType);
|
|
5631
5700
|
}
|
|
5632
|
-
function
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
const
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
data ?? '0x',
|
|
5644
|
-
serializedAccessList,
|
|
5645
|
-
...toYParitySignatureArray(transaction, signature),
|
|
5646
|
-
];
|
|
5647
|
-
return concatHex([
|
|
5648
|
-
'0x01',
|
|
5649
|
-
toRlp(serializedTransaction),
|
|
5650
|
-
]);
|
|
5701
|
+
function encodeType({ primaryType, types, }) {
|
|
5702
|
+
let result = '';
|
|
5703
|
+
const unsortedDeps = findTypeDependencies({ primaryType, types });
|
|
5704
|
+
unsortedDeps.delete(primaryType);
|
|
5705
|
+
const deps = [primaryType, ...Array.from(unsortedDeps).sort()];
|
|
5706
|
+
for (const type of deps) {
|
|
5707
|
+
result += `${type}(${types[type]
|
|
5708
|
+
.map(({ name, type: t }) => `${t} ${name}`)
|
|
5709
|
+
.join(',')})`;
|
|
5710
|
+
}
|
|
5711
|
+
return result;
|
|
5651
5712
|
}
|
|
5652
|
-
function
|
|
5653
|
-
const
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
return signature.v;
|
|
5670
|
-
return 27n + (signature.v === 35n ? 0n : 1n);
|
|
5671
|
-
}
|
|
5672
|
-
// EIP-155 (explicit chainId)
|
|
5673
|
-
if (chainId > 0)
|
|
5674
|
-
return BigInt(chainId * 2) + BigInt(35n + signature.v - 27n);
|
|
5675
|
-
// Pre-EIP-155 (no chainId)
|
|
5676
|
-
const v = 27n + (signature.v === 27n ? 0n : 1n);
|
|
5677
|
-
if (signature.v !== v)
|
|
5678
|
-
throw new InvalidLegacyVError({ v: signature.v });
|
|
5679
|
-
return v;
|
|
5680
|
-
})();
|
|
5681
|
-
serializedTransaction = [
|
|
5682
|
-
...serializedTransaction,
|
|
5683
|
-
toHex(v),
|
|
5684
|
-
signature.r,
|
|
5685
|
-
signature.s,
|
|
5713
|
+
function findTypeDependencies({ primaryType: primaryType_, types, }, results = new Set()) {
|
|
5714
|
+
const match = primaryType_.match(/^\w*/u);
|
|
5715
|
+
const primaryType = match?.[0];
|
|
5716
|
+
if (results.has(primaryType) || types[primaryType] === undefined) {
|
|
5717
|
+
return results;
|
|
5718
|
+
}
|
|
5719
|
+
results.add(primaryType);
|
|
5720
|
+
for (const field of types[primaryType]) {
|
|
5721
|
+
findTypeDependencies({ primaryType: field.type, types }, results);
|
|
5722
|
+
}
|
|
5723
|
+
return results;
|
|
5724
|
+
}
|
|
5725
|
+
function encodeField({ types, name, type, value, }) {
|
|
5726
|
+
if (types[type] !== undefined) {
|
|
5727
|
+
return [
|
|
5728
|
+
{ type: 'bytes32' },
|
|
5729
|
+
keccak256(encodeData({ data: value, primaryType: type, types })),
|
|
5686
5730
|
];
|
|
5687
5731
|
}
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5732
|
+
if (type === 'bytes') {
|
|
5733
|
+
const prepend = value.length % 2 ? '0' : '';
|
|
5734
|
+
value = `0x${prepend + value.slice(2)}`;
|
|
5735
|
+
return [{ type: 'bytes32' }, keccak256(value)];
|
|
5736
|
+
}
|
|
5737
|
+
if (type === 'string')
|
|
5738
|
+
return [{ type: 'bytes32' }, keccak256(toHex(value))];
|
|
5739
|
+
if (type.lastIndexOf(']') === type.length - 1) {
|
|
5740
|
+
const parsedType = type.slice(0, type.lastIndexOf('['));
|
|
5741
|
+
const typeValuePairs = value.map((item) => encodeField({
|
|
5742
|
+
name,
|
|
5743
|
+
type: parsedType,
|
|
5744
|
+
types,
|
|
5745
|
+
value: item,
|
|
5746
|
+
}));
|
|
5747
|
+
return [
|
|
5748
|
+
{ type: 'bytes32' },
|
|
5749
|
+
keccak256(encodeAbiParameters(typeValuePairs.map(([t]) => t), typeValuePairs.map(([, v]) => v))),
|
|
5694
5750
|
];
|
|
5695
5751
|
}
|
|
5696
|
-
return
|
|
5697
|
-
}
|
|
5698
|
-
function toYParitySignatureArray(transaction, signature) {
|
|
5699
|
-
const { r, s, v, yParity } = signature ?? transaction;
|
|
5700
|
-
if (typeof r === 'undefined')
|
|
5701
|
-
return [];
|
|
5702
|
-
if (typeof s === 'undefined')
|
|
5703
|
-
return [];
|
|
5704
|
-
if (typeof v === 'undefined' && typeof yParity === 'undefined')
|
|
5705
|
-
return [];
|
|
5706
|
-
const yParity_ = (() => {
|
|
5707
|
-
if (typeof yParity === 'number')
|
|
5708
|
-
return yParity ? toHex(1) : '0x';
|
|
5709
|
-
if (v === 0n)
|
|
5710
|
-
return '0x';
|
|
5711
|
-
if (v === 1n)
|
|
5712
|
-
return toHex(1);
|
|
5713
|
-
return v === 27n ? '0x' : toHex(1);
|
|
5714
|
-
})();
|
|
5715
|
-
return [yParity_, trim(r), trim(s)];
|
|
5716
|
-
}
|
|
5717
|
-
|
|
5718
|
-
async function signTransaction(parameters) {
|
|
5719
|
-
const { privateKey, transaction, serializer = serializeTransaction, } = parameters;
|
|
5720
|
-
const signableTransaction = (() => {
|
|
5721
|
-
// For EIP-4844 Transactions, we want to sign the transaction payload body (tx_payload_body) without the sidecars (ie. without the network wrapper).
|
|
5722
|
-
// See: https://github.com/ethereum/EIPs/blob/e00f4daa66bd56e2dbd5f1d36d09fd613811a48b/EIPS/eip-4844.md#networking
|
|
5723
|
-
if (transaction.type === 'eip4844')
|
|
5724
|
-
return {
|
|
5725
|
-
...transaction,
|
|
5726
|
-
sidecars: false,
|
|
5727
|
-
};
|
|
5728
|
-
return transaction;
|
|
5729
|
-
})();
|
|
5730
|
-
const signature = await sign({
|
|
5731
|
-
hash: keccak256(serializer(signableTransaction)),
|
|
5732
|
-
privateKey,
|
|
5733
|
-
});
|
|
5734
|
-
return serializer(transaction, signature);
|
|
5752
|
+
return [{ type }, value];
|
|
5735
5753
|
}
|
|
5736
5754
|
|
|
5737
5755
|
/**
|
|
@@ -5746,7 +5764,7 @@ async function signTypedData(parameters) {
|
|
|
5746
5764
|
hash: hashTypedData(typedData),
|
|
5747
5765
|
privateKey,
|
|
5748
5766
|
});
|
|
5749
|
-
return
|
|
5767
|
+
return serializeSignature(signature);
|
|
5750
5768
|
}
|
|
5751
5769
|
|
|
5752
5770
|
/**
|
|
@@ -5754,11 +5772,13 @@ async function signTypedData(parameters) {
|
|
|
5754
5772
|
*
|
|
5755
5773
|
* @returns A Private Key Account.
|
|
5756
5774
|
*/
|
|
5757
|
-
function privateKeyToAccount(privateKey) {
|
|
5775
|
+
function privateKeyToAccount(privateKey, options = {}) {
|
|
5776
|
+
const { nonceManager } = options;
|
|
5758
5777
|
const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false));
|
|
5759
5778
|
const address = publicKeyToAddress(publicKey);
|
|
5760
5779
|
const account = toAccount({
|
|
5761
5780
|
address,
|
|
5781
|
+
nonceManager,
|
|
5762
5782
|
async signMessage({ message }) {
|
|
5763
5783
|
return signMessage({ message, privateKey });
|
|
5764
5784
|
},
|
|
@@ -5781,9 +5801,9 @@ function privateKeyToAccount(privateKey) {
|
|
|
5781
5801
|
*
|
|
5782
5802
|
* @returns A HD Account.
|
|
5783
5803
|
*/
|
|
5784
|
-
function hdKeyToAccount(hdKey_, { accountIndex = 0, addressIndex = 0, changeIndex = 0, path } = {}) {
|
|
5804
|
+
function hdKeyToAccount(hdKey_, { accountIndex = 0, addressIndex = 0, changeIndex = 0, path, ...options } = {}) {
|
|
5785
5805
|
const hdKey = hdKey_.derive(path || `m/44'/60'/${accountIndex}'/${changeIndex}/${addressIndex}`);
|
|
5786
|
-
const account = privateKeyToAccount(toHex(hdKey.privateKey));
|
|
5806
|
+
const account = privateKeyToAccount(toHex(hdKey.privateKey), options);
|
|
5787
5807
|
return {
|
|
5788
5808
|
...account,
|
|
5789
5809
|
getHdKey: () => hdKey,
|