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

Adds signAuthorization method for EIP-7702 #407

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

jeffsmale90
Copy link

EIP-7702 defines a new struct Authorization which represents authority to set a pointer to a contract address at an EOA - effectively making the EOA perform as a smart contract.

This change adds methods to hash and sign authorizations, and to recover signer address.

Although the EIP defines the signed authorization as [chain_id, address, nonce, y_parity, r, s], the utility method returns the signature as a standard r|s|v signature for consistency with other signing methods.

See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md for details

@jeffsmale90 jeffsmale90 force-pushed the feat/sign-authorization branch from 5c46e25 to bb5e268 Compare December 19, 2024 04:13
@jeffsmale90 jeffsmale90 force-pushed the feat/sign-authorization branch from bb5e268 to b50bc64 Compare December 19, 2024 04:14
@jeffsmale90 jeffsmale90 requested a review from a team December 19, 2024 19:41
* @property contractAddress - The address of the contract being authorized.
* @property nonce - The nonce of the signing account (at the time of submission).
*/
export type Authorization = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, could Authorization be or become too generic a term in the context of signing?

Should we call this something like EIP7702Authorization?
Maybe 7702 as the filename?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that makes sense - it's already a bit of an overloaded term.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I named the file sign-eip7702-authorization.ts for a combination of clarity and consistency with the other signing files.

* @param authorization - The authorization object to validate.
* @throws {Error} If the authorization object or any of its required parameters are missing.
*/
function validateAuthorization(authorization: Authorization) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, non-exported functions at the bottom of the file to highlight what is used externally?


const [chainId, contractAddress, nonce] = authorization;

if (isNullish(chainId)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we definitely want to support / encourage cross-chain authorizations via the 0 chain ID?

Could we also validate it's not zero at this package level?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure whether or not we want to support chainId 0 - there's an argument for it, even though it's problematic (nonce likely won't match across all chains).

My preference is to support it at the utility level, and make the decision at the API level.

* @param options.authorization - The authorization data to sign.
* @returns The '0x'-prefixed hex encoded signature.
*/
export function signAuthorization({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, maybe sign7702Authorization and the same format for the other functions?

Just to add more clarity if we get other types of authorization in future?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with EIP7702 in all the places, I think I like that better than just the number.

'hex',
);

const expectedSignature =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, capitals and underscores for constants so EXPECTED_SIGNATURE etc?


describe('signAuthorization', () => {
describe('signAuthorization()', () => {
it('should produce the correct signature', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, should is redundant in test names? produces the correct signature for example.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct - it could be removed, but should is consistent across all of the existing tests 🤷

allZeroValues: [0, '0x0000000000000000000000000000000000000000', 0],
} as { [key: string]: Authorization };

for (const [label, authorization] of Object.entries(testCases)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, could also use a it.each.

…shuffled non-exported members to the bottom of the file, and renamed a few test constants to aid readability. Also used it.each for multiple test cases.
@jeffsmale90
Copy link
Author

@matthewwalsh0 thanks for the review! I made all of the changes you recommended, except for validating chainId !== 0, as I think this should be an API concern, rather than a utility concern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants