-
-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add CAIP-25 permission and adapters to
@metamask/multichain
(#…
…4784) ## Explanation This PR updates `@metamask/multichain` to provide types, CAIP-25 permission, and helpers/adapters for the new permission, which can be shared across the extension & mobile clients. These tools and utilities will be used in both clients (mobile + extension)'s multichain API implementations. ### File Overview * `packages/multichain/src/adapters/`: Helpers that get and set legacy permission values from and to the new CAIP-25 permission * `packages/multichain/src/caip25Permission.ts`: Constants, types, mutators, and a specification builder for a CAIP-25 permission * `packages/multichain/src/index.ts`: Barrel export * `packages/multichain/src/scope/`: Types for [CAIP-217 ](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-217.md) and our internal normalized/flattened version of them. Additionally contains helpers for validating shape, normalizing/merging, and checking support (i.e. if the wallet is able to serve the chain with it's requested methods and notifications) ## References Upstream: #4812 Downstream: #4813 Key Multichain API Standards implemented here: - [CAIP-217](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-217.md) - `scope` defintion Open PR that uses this new package for migrating the legacy permissions to CAIP-25 permission in the extension: MetaMask/metamask-extension#27847 ## Changelog ### `@metamask/multichain` - **ADDED**: TODO ## Checklist - [X] I've updated the test suite for new or updated code as appropriate - [X] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [X] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --------- Co-authored-by: Alex <[email protected]> Co-authored-by: Mark Stacey <[email protected]> Co-authored-by: Elliot Winkler <[email protected]>
- Loading branch information
1 parent
db83e28
commit 1e7d70e
Showing
29 changed files
with
4,666 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
263 changes: 263 additions & 0 deletions
263
packages/multichain/src/adapters/caip-permission-adapter-eth-accounts.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
import type { Caip25CaveatValue } from '../caip25Permission'; | ||
import { | ||
getEthAccounts, | ||
setEthAccounts, | ||
} from './caip-permission-adapter-eth-accounts'; | ||
|
||
describe('CAIP-25 eth_accounts adapters', () => { | ||
describe('getEthAccounts', () => { | ||
it('returns an empty array if the required scopes are empty', () => { | ||
const ethAccounts = getEthAccounts({ | ||
requiredScopes: {}, | ||
optionalScopes: {}, | ||
}); | ||
expect(ethAccounts).toStrictEqual([]); | ||
}); | ||
it('returns an empty array if the scope objects have no accounts', () => { | ||
const ethAccounts = getEthAccounts({ | ||
requiredScopes: { | ||
'eip155:1': { methods: [], notifications: [], accounts: [] }, | ||
'eip155:2': { methods: [], notifications: [], accounts: [] }, | ||
}, | ||
optionalScopes: {}, | ||
}); | ||
expect(ethAccounts).toStrictEqual([]); | ||
}); | ||
it('returns an empty array if the scope objects have no eth accounts', () => { | ||
const ethAccounts = getEthAccounts({ | ||
requiredScopes: { | ||
'bip122:000000000019d6689c085ae165831e93': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', | ||
], | ||
}, | ||
}, | ||
optionalScopes: {}, | ||
}); | ||
expect(ethAccounts).toStrictEqual([]); | ||
}); | ||
|
||
it('returns the unique set of EIP155 accounts from the CAIP-25 caveat value', () => { | ||
const ethAccounts = getEthAccounts({ | ||
requiredScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:1:0x1', 'eip155:1:0x2'], | ||
}, | ||
'eip155:5': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:5:0x2', 'eip155:1:0x3'], | ||
}, | ||
'bip122:000000000019d6689c085ae165831e93': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', | ||
], | ||
}, | ||
}, | ||
optionalScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:1:0x1', 'eip155:1:0x4'], | ||
}, | ||
'eip155:10': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [], | ||
}, | ||
'eip155:100': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:100:0x100'], | ||
}, | ||
'wallet:eip155': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['wallet:eip155:0x5'], | ||
}, | ||
}, | ||
}); | ||
|
||
expect(ethAccounts).toStrictEqual([ | ||
'0x1', | ||
'0x2', | ||
'0x4', | ||
'0x3', | ||
'0x100', | ||
'0x5', | ||
]); | ||
}); | ||
}); | ||
|
||
describe('setEthAccounts', () => { | ||
it('returns a CAIP-25 caveat value with all EIP-155 scopeObject.accounts set to CAIP-10 account addresses formed from the accounts param', () => { | ||
const input: Caip25CaveatValue = { | ||
requiredScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:1:0x1', 'eip155:1:0x2'], | ||
}, | ||
'eip155:5': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:5:0x2', 'eip155:1:0x3'], | ||
}, | ||
'bip122:000000000019d6689c085ae165831e93': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', | ||
], | ||
}, | ||
}, | ||
optionalScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:1:0x1', 'eip155:1:0x4'], | ||
}, | ||
'eip155:10': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [], | ||
}, | ||
'eip155:100': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:100:0x100'], | ||
}, | ||
'wallet:eip155': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [], | ||
}, | ||
wallet: { | ||
methods: [], | ||
notifications: [], | ||
accounts: [], | ||
}, | ||
}, | ||
isMultichainOrigin: false, | ||
}; | ||
|
||
const result = setEthAccounts(input, ['0x1', '0x2', '0x3']); | ||
expect(result).toStrictEqual({ | ||
requiredScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:1:0x1', 'eip155:1:0x2', 'eip155:1:0x3'], | ||
}, | ||
'eip155:5': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:5:0x1', 'eip155:5:0x2', 'eip155:5:0x3'], | ||
}, | ||
'bip122:000000000019d6689c085ae165831e93': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', | ||
], | ||
}, | ||
}, | ||
optionalScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:1:0x1', 'eip155:1:0x2', 'eip155:1:0x3'], | ||
}, | ||
'eip155:10': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:10:0x1', 'eip155:10:0x2', 'eip155:10:0x3'], | ||
}, | ||
'eip155:100': { | ||
methods: [], | ||
notifications: [], | ||
accounts: ['eip155:100:0x1', 'eip155:100:0x2', 'eip155:100:0x3'], | ||
}, | ||
'wallet:eip155': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'wallet:eip155:0x1', | ||
'wallet:eip155:0x2', | ||
'wallet:eip155:0x3', | ||
], | ||
}, | ||
wallet: { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'wallet:eip155:0x1', | ||
'wallet:eip155:0x2', | ||
'wallet:eip155:0x3', | ||
], | ||
}, | ||
}, | ||
isMultichainOrigin: false, | ||
}); | ||
}); | ||
|
||
it('returns a CAIP-25 caveat value with missing "wallet:eip155" optional scope filled in, forming CAIP-10 account addresses from the accounts param', () => { | ||
const input: Caip25CaveatValue = { | ||
requiredScopes: {}, | ||
optionalScopes: {}, | ||
isMultichainOrigin: false, | ||
}; | ||
|
||
const result = setEthAccounts(input, ['0x1', '0x2', '0x3']); | ||
expect(result).toStrictEqual({ | ||
requiredScopes: {}, | ||
optionalScopes: { | ||
'wallet:eip155': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [ | ||
'wallet:eip155:0x1', | ||
'wallet:eip155:0x2', | ||
'wallet:eip155:0x3', | ||
], | ||
}, | ||
}, | ||
isMultichainOrigin: false, | ||
}); | ||
}); | ||
|
||
it('does not modify the input CAIP-25 caveat value object in place', () => { | ||
const input: Caip25CaveatValue = { | ||
requiredScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [], | ||
}, | ||
}, | ||
optionalScopes: {}, | ||
isMultichainOrigin: false, | ||
}; | ||
|
||
const result = setEthAccounts(input, ['0x1', '0x2', '0x3']); | ||
expect(input).toStrictEqual({ | ||
requiredScopes: { | ||
'eip155:1': { | ||
methods: [], | ||
notifications: [], | ||
accounts: [], | ||
}, | ||
}, | ||
optionalScopes: {}, | ||
isMultichainOrigin: false, | ||
}); | ||
expect(input).not.toStrictEqual(result); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.