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