Skip to content

Commit

Permalink
feat: add checksum addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
janek26 committed May 4, 2022
1 parent 5a40cd6 commit 2d32ed8
Show file tree
Hide file tree
Showing 4 changed files with 868 additions and 543 deletions.
31 changes: 30 additions & 1 deletion __tests__/utils/address.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { addAddressPadding, validateAndParseAddress } from '../../src/utils/address';
import {
addAddressPadding,
getChecksumAddress,
validateAndParseAddress,
validateChecksumAddress,
} from '../../src/utils/address';
// import { addHexPrefix, removeHexPrefix } from '../../src/utils/encode';

describe('validateAndParseAddress', () => {
Expand All @@ -14,3 +19,27 @@ describe('validateAndParseAddress', () => {
return expect(validateAndParseAddress(addr)).toEqual(`${addAddressPadding(addr)}`);
});
});

describe('address checksums', () => {
test('should be able to calculate checksum address', () => {
const checksumAddress = getChecksumAddress(
'0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914'
);
expect(checksumAddress).toEqual(
'0x02FD23D9182193775423497Fc0c472E156C57C69E4089a1967fb288a2D84e914'
);
});
test('should be able to verify checksum address', () => {
const isValid = validateChecksumAddress(
'0x02FD23D9182193775423497Fc0c472E156C57C69E4089a1967fb288a2D84e914'
);
expect(isValid).toEqual(true);
});
test('calculated checksum address should validate', () => {
const checksumAddress = getChecksumAddress(
'0x26cb0b500d175111341fabb53bf7fa4f5a0b8c5cbb31896cec1e8383a5edda8'
);
const isValid = validateChecksumAddress(checksumAddress);
expect(isValid).toEqual(true);
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"typescript": "^4.4.4"
},
"dependencies": {
"@ethersproject/bytes": "^5.6.1",
"axios": "^0.23.0",
"bn.js": "^5.2.0",
"elliptic": "^6.5.4",
Expand Down
36 changes: 28 additions & 8 deletions src/utils/address.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/* eslint-disable no-bitwise */
import { arrayify } from '@ethersproject/bytes';

import { MASK_251, ZERO } from '../constants';
import { addHexPrefix, removeHexPrefix } from './encode';
import { assertInRange } from './number';
import { pedersen } from './hash';
import { BigNumberish, assertInRange, toBN, toHex } from './number';

export function addAddressPadding(address: string): string {
return addHexPrefix(removeHexPrefix(address).padStart(64, '0'));
export function addAddressPadding(address: BigNumberish): string {
return addHexPrefix(removeHexPrefix(toHex(toBN(address))).padStart(64, '0'));
}

export function validateAndParseAddress(address: string): string {
if (typeof address !== 'string') {
throw new Error('Invalid Address Type');
}

export function validateAndParseAddress(address: BigNumberish): string {
assertInRange(address, ZERO, MASK_251, 'Starknet Address');

const result = addAddressPadding(address);
Expand All @@ -21,3 +21,23 @@ export function validateAndParseAddress(address: string): string {

return result;
}

export const getChecksumAddress = (address: BigNumberish): string => {
const chars = removeHexPrefix(validateAndParseAddress(address)).toLowerCase().split('');
const hashed = arrayify(pedersen([0, address]), { hexPad: 'left' }); // as the hash will be 251 bits (63 chars) we need to pad it to 64 chars without changing the number value ("left")

for (let i = 0; i < chars.length; i += 2) {
if (hashed[i >> 1] >> 4 >= 8) {
chars[i] = chars[i].toUpperCase();
}
if ((hashed[i >> 1] & 0x0f) >= 8) {
chars[i + 1] = chars[i + 1].toUpperCase();
}
}

return addHexPrefix(chars.join(''));
};

export const validateChecksumAddress = (address: string): boolean => {
return getChecksumAddress(address) === address;
};

0 comments on commit 2d32ed8

Please sign in to comment.