Skip to content

Commit

Permalink
feat(multichain): normalize address helpers (#25022)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

New helpers to normalize address that can also be used in a non-EVM
context.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/25022?quickstart=1)

## **Related issues**

None

## **Manual testing steps**

None

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
ccharly authored Jun 5, 2024
1 parent 37f90a0 commit 13bd829
Show file tree
Hide file tree
Showing 13 changed files with 348 additions and 208 deletions.
96 changes: 96 additions & 0 deletions app/scripts/lib/multichain/address.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
isEthAddress,
normalizeAddress,
normalizeSafeAddress,
} from './address';

type TestAddress = {
address: string;
normalizedAddress: string;
checksumAddress: string;
};

const ETH_ADDRESSES = [
// Lower-case address
{
address: '0x6431726eee67570bf6f0cf892ae0a3988f03903f',
normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f',
checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F',
},
// Checksum address
{
address: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F',
normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f',
checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F',
},
];

const NON_EVM_ADDRESSES = [
{
address: '0xdeadbeef',
},
{
address: 'bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2',
},
];

describe('address', () => {
describe('isEthAddress', () => {
// @ts-expect-error This is missing from the Mocha type definitions
it.each(ETH_ADDRESSES)(
'returns true if address is an ethereum address: $address',
({ address }: TestAddress) => {
expect(isEthAddress(address)).toBe(true);
expect(isEthAddress(address.toLowerCase())).toBe(true);
},
);

// @ts-expect-error This is missing from the Mocha type definitions
it.each(NON_EVM_ADDRESSES)(
'returns false if address is not an ethereum address: $address',
({ address }: TestAddress) => {
expect(isEthAddress(address)).toBe(false);
},
);
});

describe('normalizeAddress', () => {
// @ts-expect-error This is missing from the Mocha type definitions
it.each(ETH_ADDRESSES)(
'normalizes address: $address',
({ address, normalizedAddress }: TestAddress) => {
expect(normalizeAddress(address)).toBe(normalizedAddress);
expect(normalizeAddress(address.toLowerCase())).toBe(normalizedAddress);
},
);

// @ts-expect-error This is missing from the Mocha type definitions
it.each(NON_EVM_ADDRESSES)(
'returns the original address if its a non-EVM address',
({ address }: TestAddress) => {
expect(normalizeAddress(address)).toBe(address);
},
);
});

describe('normalizeSafeAddress', () => {
// @ts-expect-error This is missing from the Mocha type definitions
it.each(ETH_ADDRESSES)(
'normalizes address to its "safe" form: $address to: $checksumAddress',
({ address, checksumAddress }: TestAddress) => {
expect(normalizeSafeAddress(address)).toBe(checksumAddress);
expect(normalizeSafeAddress(address.toLowerCase())).toBe(
checksumAddress,
);
},
);

// @ts-expect-error This is missing from the Mocha type definitions
it.each(NON_EVM_ADDRESSES)(
'returns the original address if its a non-EVM address',
({ address }: TestAddress) => {
expect(normalizeSafeAddress(address)).toBe(address);
},
);
});
});
40 changes: 40 additions & 0 deletions app/scripts/lib/multichain/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Hex, isValidHexAddress } from '@metamask/utils';
import { normalize as normalizeEthAddress } from '@metamask/eth-sig-util';
import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils';

/**
* Checks if an address is an ethereum one.
*
* @param address - An address.
* @returns True if the address is an ethereum one, false otherwise.
*/
export function isEthAddress(address: string): boolean {
return isValidHexAddress(address as Hex);
}

/**
* Normalize an address. The address might be returned as-is, if there's no normalizer available.
*
* @param address - An address to normalize.
* @returns The normalized address.
*/
export function normalizeAddress(address: string): string {
// NOTE: We assume that the overhead over checking the address format
// at runtime is small
return isEthAddress(address)
? (normalizeEthAddress(address) as string)
: address;
}

/**
* Normalize an address to a "safer" representation. The address might be returned as-is, if
* there's no normalizer available.
*
* @param address - An address to normalize.
* @returns The "safer" normalized address.
*/
export function normalizeSafeAddress(address: string): string {
// NOTE: We assume that the overhead over checking the address format
// at runtime is small
return isEthAddress(address) ? toChecksumHexAddress(address) : address;
}
78 changes: 39 additions & 39 deletions lavamoat/browserify/beta/policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@
"packages": {
"@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": true,
"@metamask/eth-json-rpc-middleware>safe-stable-stringify": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/eth-sig-util": true,
"@metamask/providers>@metamask/rpc-errors": true,
"@metamask/utils": true,
"pify": true,
Expand All @@ -1054,8 +1054,8 @@
"@ethereumjs/tx": true,
"@ethereumjs/tx>@ethereumjs/rlp": true,
"@ethereumjs/tx>@ethereumjs/util": true,
"@metamask/eth-sig-util": true,
"@metamask/eth-trezor-keyring>hdkey": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"browserify>buffer": true,
"webpack>events": true
}
Expand All @@ -1066,16 +1066,46 @@
"watchify>xtend": true
}
},
"@metamask/eth-sig-util": {
"packages": {
"@ethereumjs/tx>@ethereumjs/util": true,
"@ethereumjs/tx>ethereum-cryptography": true,
"@metamask/abi-utils": true,
"@metamask/eth-sig-util>tweetnacl": true,
"@metamask/eth-sig-util>tweetnacl-util": true,
"@metamask/utils": true,
"browserify>buffer": true
}
},
"@metamask/eth-sig-util>tweetnacl": {
"globals": {
"crypto": true,
"msCrypto": true,
"nacl": "write"
},
"packages": {
"browserify>browser-resolve": true
}
},
"@metamask/eth-sig-util>tweetnacl-util": {
"globals": {
"atob": true,
"btoa": true
},
"packages": {
"browserify>browser-resolve": true
}
},
"@metamask/eth-snap-keyring": {
"globals": {
"URL": true,
"console.error": true
},
"packages": {
"@ethereumjs/tx": true,
"@metamask/eth-sig-util": true,
"@metamask/eth-snap-keyring>uuid": true,
"@metamask/keyring-api": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/utils": true,
"superstruct": true,
"webpack>events": true
Expand Down Expand Up @@ -1218,7 +1248,7 @@
},
"@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": {
"packages": {
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/eth-sig-util": true,
"@trezor/connect-web>tslib": true
}
},
Expand Down Expand Up @@ -1449,11 +1479,11 @@
"packages": {
"@ethereumjs/tx>@ethereumjs/util": true,
"@metamask/browser-passworder": true,
"@metamask/eth-sig-util": true,
"@metamask/keyring-controller>@metamask/base-controller": true,
"@metamask/keyring-controller>@metamask/eth-hd-keyring": true,
"@metamask/keyring-controller>@metamask/eth-simple-keyring": true,
"@metamask/keyring-controller>ethereumjs-wallet": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/name-controller>async-mutex": true,
"@metamask/utils": true
}
Expand All @@ -1473,7 +1503,7 @@
"packages": {
"@ethereumjs/tx>@ethereumjs/util": true,
"@ethereumjs/tx>ethereum-cryptography": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/eth-sig-util": true,
"@metamask/scure-bip39": true,
"@metamask/utils": true,
"browserify>buffer": true
Expand All @@ -1483,7 +1513,7 @@
"packages": {
"@ethereumjs/tx>@ethereumjs/util": true,
"@ethereumjs/tx>ethereum-cryptography": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/eth-sig-util": true,
"@metamask/utils": true,
"browserify>buffer": true,
"mocha>serialize-javascript>randombytes": true
Expand Down Expand Up @@ -1564,8 +1594,8 @@
"@metamask/message-manager": {
"packages": {
"@metamask/base-controller": true,
"@metamask/eth-sig-util": true,
"@metamask/message-manager>@metamask/controller-utils": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/message-manager>jsonschema": true,
"@metamask/utils": true,
"browserify>buffer": true,
Expand All @@ -1591,36 +1621,6 @@
"eth-ens-namehash": true
}
},
"@metamask/message-manager>@metamask/eth-sig-util": {
"packages": {
"@ethereumjs/tx>@ethereumjs/util": true,
"@ethereumjs/tx>ethereum-cryptography": true,
"@metamask/abi-utils": true,
"@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true,
"@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true,
"@metamask/utils": true,
"browserify>buffer": true
}
},
"@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": {
"globals": {
"crypto": true,
"msCrypto": true,
"nacl": "write"
},
"packages": {
"browserify>browser-resolve": true
}
},
"@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": {
"globals": {
"atob": true,
"btoa": true
},
"packages": {
"browserify>browser-resolve": true
}
},
"@metamask/message-manager>jsonschema": {
"packages": {
"browserify>url": true
Expand Down Expand Up @@ -1953,7 +1953,7 @@
"@metamask/signature-controller>@metamask/message-manager": {
"packages": {
"@metamask/controller-utils": true,
"@metamask/message-manager>@metamask/eth-sig-util": true,
"@metamask/eth-sig-util": true,
"@metamask/message-manager>jsonschema": true,
"@metamask/signature-controller>@metamask/base-controller": true,
"@metamask/utils": true,
Expand Down
Loading

0 comments on commit 13bd829

Please sign in to comment.