Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(EIP712): allow string chainId for domain #1692

Merged
merged 9 commits into from
Jan 17, 2025
2 changes: 1 addition & 1 deletion packages/aws-kms-adapter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@
"@vechain/sdk-network": "2.0.0-beta.1",
"asn1js": "^3.0.5",
"ethers": "6.13.5",
"viem": "^2.21.54"
"viem": "^2.22.8"
}
}
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"abitype": "^1.0.8",
"ethers": "6.13.5",
"fast-json-stable-stringify": "^2.1.0",
"viem": "^2.21.54"
"viem": "^2.22.8"
},
"devDependencies": {
"bignumber.js": "^9.1.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/network/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"abitype": "^1.0.8",
"ethers": "6.13.5",
"isomorphic-ws": "^5.0.0",
"viem": "^2.21.54",
"viem": "^2.22.8",
"ws": "^8.18.0"
},
"devDependencies": {
Expand Down
11 changes: 7 additions & 4 deletions packages/network/src/signer/signers/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type TransactionClause } from '@vechain/sdk-core';
import type {
TypedDataDomain as viemTypedDataDomain,
TypedDataParameter as viemTypedDataParameter
TypedDataDomain as ViemTypedDataDomain,
TypedDataParameter as ViemTypedDataParameter
} from 'viem';
import {
type HardhatVeChainProvider,
Expand All @@ -20,8 +20,11 @@ type AvailableVeChainProviders = VeChainProvider | HardhatVeChainProvider;
* EIP-712 types in case we change the provider (viem as of now)
*/

type TypedDataDomain = viemTypedDataDomain;
type TypedDataParameter = viemTypedDataParameter;
type TypedDataDomain = Omit<ViemTypedDataDomain, 'chainId'> & {
chainId: number | bigint | string | undefined;
};

type TypedDataParameter = ViemTypedDataParameter;

/**
* Type for transaction input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import {
JSONRPCInvalidParams,
SignerMethodError
} from '@vechain/sdk-errors';
import { hashTypedData } from 'viem';
import {
hashTypedData,
type TypedDataDomain as ViemTypedDataDomain
} from 'viem';
import { RPC_METHODS } from '../../../provider/utils/const/rpc-mapper/rpc-methods';
import { type TransactionSimulationResult } from '../../../thor-client';
import { vnsUtils } from '../../../utils';
Expand Down Expand Up @@ -409,6 +412,46 @@ abstract class VeChainAbstractSigner implements VeChainSigner {
return primaryTypes[0];
}

/**
* Viem does not check the type of the domain object on runtime at least in version 2.22.8
* @param obj unknown object to check if it is a ViemTypedDataDomain
* @returns true if the object is a ViemTypedDataDomain
*/
private isViemTypedDataDomain(obj: unknown): obj is ViemTypedDataDomain {
if (typeof obj !== 'object' || obj === null) {
return false;
}

const expectedKeys = [
'name',
'version',
'chainId',
'verifyingContract',
'salt'
];
const objKeys = Object.keys(obj);

// Check for unexpected keys
for (const key of objKeys) {
if (!expectedKeys.includes(key)) {
return false;
}
}

// salt and verifyingContract are dynamic types, should be checked by viem
const domain = obj as ViemTypedDataDomain;
return (
(typeof domain.name === 'undefined' ||
typeof domain.name === 'string') &&
(typeof domain.version === 'undefined' ||
typeof domain.version === 'string') &&
(typeof domain.chainId === 'undefined' ||
typeof domain.chainId === 'number' ||
typeof domain.chainId === 'bigint' ||
typeof domain.chainId === 'string')
);
}

/**
* Signs the [[link-eip-712]] typed data.
*
Expand All @@ -426,9 +469,23 @@ abstract class VeChainAbstractSigner implements VeChainSigner {
primaryType?: string
): Promise<string> {
try {
const parsedDomain: ViemTypedDataDomain = {
...domain,
chainId:
typeof domain.chainId === 'string'
? BigInt(domain.chainId)
: domain.chainId
};
if (!this.isViemTypedDataDomain(parsedDomain)) {
throw new SignerMethodError(
'VeChainAbstractSigner.signTypedData',
'The domain is not a valid object.',
{ domain }
);
}
const payload = Hex.of(
hashTypedData({
domain,
domain: parsedDomain,
types,
primaryType: primaryType ?? this.deducePrimaryType(types), // Deduce the primary type if not provided
message
Expand All @@ -437,6 +494,9 @@ abstract class VeChainAbstractSigner implements VeChainSigner {

return await this.signPayload(payload);
} catch (error) {
if (error instanceof SignerMethodError) {
throw error;
}
throw new SignerMethodError(
'VeChainAbstractSigner.signTypedData',
'The typed data could not be signed.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,42 @@ describe('VeChain base signer tests', () => {
eip712TestCases.valid.data
);
expect(actualWithoutPrimaryType).toBe(expected);

// Using VeChain chainId as string and bigint
const vechainChainId =
'1176455790972829965191905223412607679856028701100105089447013101863';
const expectedVeChain = await new Wallet(
eip712TestCases.valid.privateKey
).signTypedData(
{
...eip712TestCases.valid.domain,
chainId: vechainChainId
},
eip712TestCases.valid.types,
eip712TestCases.valid.data
);
const actualWithStringChainId =
await privateKeySigner.signTypedData(
{
...eip712TestCases.valid.domain,
chainId: vechainChainId
},
eip712TestCases.valid.types,
eip712TestCases.valid.data,
eip712TestCases.valid.primaryType
);
expect(actualWithStringChainId).toBe(expectedVeChain);
const actualWithBigintChainId =
await privateKeySigner.signTypedData(
{
...eip712TestCases.valid.domain,
chainId: BigInt(vechainChainId)
},
eip712TestCases.valid.types,
eip712TestCases.valid.data,
eip712TestCases.valid.primaryType
);
expect(actualWithBigintChainId).toBe(expectedVeChain);
});
});
});
18 changes: 9 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11559,10 +11559,10 @@ outvariant@^1.4.0, outvariant@^1.4.3:
resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873"
integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==

ox@0.1.2:
version "0.1.2"
resolved "https://registry.npmjs.org/ox/-/ox-0.1.2.tgz#0f791be2ccabeaf4928e6d423498fe1c8094e560"
integrity sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww==
ox@0.6.0:
version "0.6.0"
resolved "https://registry.npmjs.org/ox/-/ox-0.6.0.tgz#ba8f89d68b5e8afe717c8a947ffacc0669ea155d"
integrity sha512-blUzTLidvUlshv0O02CnLFqBLidNzPoAZdIth894avUAotTuWziznv6IENv5idRuOSSP3dH8WzcYw84zVdu0Aw==
dependencies:
"@adraffy/ens-normalize" "^1.10.1"
"@noble/curves" "^1.6.0"
Expand Down Expand Up @@ -14391,18 +14391,18 @@ vfile@^6.0.0:
"@types/unist" "^3.0.0"
vfile-message "^4.0.0"

viem@^2.21.54:
version "2.21.54"
resolved "https://registry.yarnpkg.com/viem/-/viem-2.21.54.tgz#76d6f86ab8809078f1ac140ac1a2beadbc86b9f6"
integrity sha512-G9mmtbua3UtnVY9BqAtWdNp+3AO+oWhD0B9KaEsZb6gcrOWgmA4rz02yqEMg+qW9m6KgKGie7q3zcHqJIw6AqA==
viem@^2.22.8:
version "2.22.8"
resolved "https://registry.npmjs.org/viem/-/viem-2.22.8.tgz#fbc51215133066b89730e9a2aa2c7c0cb975a8e8"
integrity sha512-iB3PW/a/qzpYbpjo3R662u6a/zo6piZHez/N/bOC25C79FYXBCs8mQDqwiHk3FYErUhS4KVZLabKV9zGMd+EgQ==
dependencies:
"@noble/curves" "1.7.0"
"@noble/hashes" "1.6.1"
"@scure/bip32" "1.6.0"
"@scure/bip39" "1.5.0"
abitype "1.0.7"
isows "1.0.6"
ox "0.1.2"
ox "0.6.0"
webauthn-p256 "0.0.10"
ws "8.18.0"

Expand Down
Loading