Skip to content

Commit d07ba97

Browse files
authored
fix(smart-wallet-sdk): add parseAddressDelegation (#344)
1 parent a7fb8d7 commit d07ba97

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

sdks/smart-wallet-sdk/src/constants.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { ChainId } from '@uniswap/sdk-core'
22

3+
// https://eips.ethereum.org/EIPS/eip-7702
4+
export const DELEGATION_MAGIC_PREFIX = '0xef0100';
5+
36
/**
47
* The target address for self-calls is address(0)
58
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { DELEGATION_MAGIC_PREFIX } from "../constants";
2+
3+
import { Delegation } from "./delegation";
4+
5+
6+
describe('Delegation', () => {
7+
describe('parseFromCode', () => {
8+
const address = `1111111111111111111111111111111111111111`; // address length without 0x prefix
9+
it('parses out the delegation', () => {
10+
const delegation = Delegation.parseFromCode(`${DELEGATION_MAGIC_PREFIX}${address}`);
11+
expect(delegation).toBe(`0x${address}`)
12+
})
13+
14+
it('throws an error if there is no delegation', () => {
15+
const emptyDelegation = '' as `0x${string}`;
16+
expect(() => Delegation.parseFromCode(emptyDelegation)).toThrow()
17+
})
18+
19+
it('throws an error if the magic prefix is incorrect', () => {
20+
const incorrectMagicPrefix = '0x000000' as `0x${string}`;
21+
expect(() => Delegation.parseFromCode(`${incorrectMagicPrefix}${address}`)).toThrow(
22+
`Invalid delegation magic prefix: ${incorrectMagicPrefix}`
23+
)
24+
})
25+
})
26+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Address, TransactionEIP7702 } from 'viem'
2+
import { recoverAuthorizationAddress, SignedAuthorization, SignedAuthorizationList } from 'viem/experimental'
3+
4+
import { DELEGATION_MAGIC_PREFIX } from '../constants'
5+
6+
export type RecoveredAuthorizationMap = Record<Address, SignedAuthorization>
7+
8+
export class Delegation {
9+
/**
10+
* Recovers the signers of each authorization within the list sent in the transaction
11+
* @dev this can also return just the contractAddress each signer is delegated to
12+
* @param transaction : TransactionEIP7702
13+
* @returns : Promise<RecoveredAuthorizationMap>
14+
*/
15+
public static parseAuthorizationListFromTransaction(transaction: TransactionEIP7702): Promise<RecoveredAuthorizationMap> {
16+
return this.parseAuthorizationList(transaction.authorizationList)
17+
}
18+
19+
/**
20+
* Recovers the signers of each authorization in the list
21+
* @param authorizationList : SignedAuthorizationList
22+
* @returns : Promise<RecoveredAuthorizationMap>
23+
*/
24+
public static async parseAuthorizationList(authorizationList: SignedAuthorizationList): Promise<RecoveredAuthorizationMap> {
25+
// recover each authorization
26+
const result: RecoveredAuthorizationMap = {}
27+
for (const authorization of authorizationList) {
28+
const signer = await recoverAuthorizationAddress({ authorization })
29+
result[signer] = authorization
30+
}
31+
return result
32+
}
33+
34+
/// Parses a delegation from an address's code
35+
/// @dev will throw if the code is not a valid delegation per EIP7702 spec
36+
public static parseFromCode(code: `0x${string}`): Address {
37+
if(code.length !== 48) {
38+
throw new Error(`Invalid delegation length: ${code.length}`)
39+
}
40+
// parse out magic prefix which is 4 bytes
41+
const magicPrefix = code.slice(0, 8)
42+
if(magicPrefix !== DELEGATION_MAGIC_PREFIX) {
43+
throw new Error(`Invalid delegation magic prefix: ${magicPrefix}`)
44+
}
45+
const delegation = code.slice(8)
46+
return `0x${delegation}` as Address
47+
}
48+
}

0 commit comments

Comments
 (0)