Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 247 additions & 46 deletions src/utils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,66 +505,267 @@ describe('utils', () => {

describe('getFormattedAddress', () => {
describe('when explicitly passing an address type', () => {
test('returns a checksummed EVM address', () => {
const address = '0x91fd2c8d24767db4ece7069aa27832ffaf8590f3';
expect(getFormattedAddress(address, 'evm')).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});
describe('EVM type parsing', () => {
test('should return checksummed EVM address when given checksummed input', () => {
const address = '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3';
expect(getFormattedAddress(address, 'evm')).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('returns a padded and lowercased starknet address', () => {
const address =
'0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(getFormattedAddress(address, 'starknet')).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});
test('should return checksummed EVM address when given lowercase input', () => {
const address = '0x91fd2c8d24767db4ece7069aa27832ffaf8590f3';
expect(getFormattedAddress(address, 'evm')).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('returns an EVM address as starknet address', () => {
const address = '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3';
expect(getFormattedAddress(address, 'starknet')).toEqual(
'0x00000000000000000000000091fd2c8d24767db4ece7069aa27832ffaf8590f3'
);
});
test('should return checksummed EVM address when given uppercase input', () => {
const uppercaseAddress = '0x91FD2C8D24767DB4ECE7069AA27832FFAF8590F3';
expect(getFormattedAddress(uppercaseAddress, 'evm')).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('should throw error when forcing EVM parsing on address with uppercase 0X prefix', () => {
const uppercaseHexPrefix =
'0X91FD2C8D24767DB4ECE7069AA27832FFAF8590F3';
expect(() => getFormattedAddress(uppercaseHexPrefix, 'evm')).toThrow(
'Invalid evm address: 0X91FD2C8D24767DB4ECE7069AA27832FFAF8590F3'
);
});

test('should throw error when forcing EVM parsing on invalid mixed case address', () => {
const invalidMixedCaseAddress =
'0x91Fd2C8d24767Db4eCe7069aA27832FfaF8590F3';
expect(() =>
getFormattedAddress(invalidMixedCaseAddress, 'evm')
).toThrow(
'Invalid evm address: 0x91Fd2C8d24767Db4eCe7069aA27832FfaF8590F3'
);
});

test('throws an error when the address is not a starknet address', () => {
const address = 'hello';
expect(() => getFormattedAddress(address, 'starknet')).toThrow();
test('should throw error when address is not an EVM address', () => {
const address =
'0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(() => getFormattedAddress(address, 'evm')).toThrow(
'Invalid evm address: 0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});
});

test('throws an error when the address is not an EVM address', () => {
const address =
'0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(() => getFormattedAddress(address, 'evm')).toThrow();
describe('Starknet type parsing', () => {
test('should return padded and lowercased starknet address when given unpadded input', () => {
const address =
'0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(getFormattedAddress(address, 'starknet')).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return padded and lowercased starknet address when given lowercase input', () => {
const address =
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(getFormattedAddress(address, 'starknet')).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return padded and lowercased starknet address when given uppercase Starknet input', () => {
const uppercaseAddress =
'0x02A0A8F3B6097E7A6BD7649DEB30715323072A159C0E6B71B689BD245C146CC0';
expect(getFormattedAddress(uppercaseAddress, 'starknet')).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return padded and lowercased starknet address when given checksum Starknet input', () => {
const checksumAddress =
'0x02a0a8F3B6097e7A6bd7649DEB30715323072A159c0E6B71B689Bd245c146cC0';
expect(getFormattedAddress(checksumAddress, 'starknet')).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return padded and lowercased starknet address when given mixed case Starknet input', () => {
const mixedCaseAddress =
'0x02A0a8F3B6097e7A6bD7649DEB30715323072a159C0e6b71B689BD245c146Cc0';
expect(getFormattedAddress(mixedCaseAddress, 'starknet')).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return EVM address as starknet address when explicitly formatted', () => {
const address = '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3';
expect(getFormattedAddress(address, 'starknet')).toEqual(
'0x00000000000000000000000091fd2c8d24767db4ece7069aa27832ffaf8590f3'
);
});

test('should throw error when given invalid Starknet address with explicit format', () => {
const invalidStarknetAddress = '0xinvalidstarknetaddresshere';
expect(() =>
getFormattedAddress(invalidStarknetAddress, 'starknet')
).toThrow('Invalid starknet address: 0xinvalidstarknetaddresshere');
});
});
});

describe('when not passing an address type', () => {
test('returns a checksummed EVM address for an EVM input', () => {
const address = '0x91fd2c8d24767db4ece7069aa27832ffaf8590f3';
expect(getFormattedAddress(address)).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});
describe('EVM address auto-detection', () => {
test('should auto-detect and format valid 42-char lowercase EVM address', () => {
const address = '0x91fd2c8d24767db4ece7069aa27832ffaf8590f3';
expect(getFormattedAddress(address)).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('returns a padded and lowercased starknet address for a Starknet input', () => {
const address =
'0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(getFormattedAddress(address)).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
test('should auto-detect and format valid 42-char uppercase EVM address', () => {
const address = '0x91FD2C8D24767DB4ECE7069AA27832FFAF8590F3';
expect(getFormattedAddress(address)).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('should auto-detect and format valid 42-char checksummed EVM address', () => {
const address = '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3';
expect(getFormattedAddress(address)).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('should throw error when auto-detecting invalid mixed case EVM address', () => {
const invalidMixedCaseAddress =
'0x91Fd2C8d24767Db4eCe7069aA27832FfaF8590F3';
expect(() => getFormattedAddress(invalidMixedCaseAddress)).toThrow(
'Invalid evm address: 0x91Fd2C8d24767Db4eCe7069aA27832FfaF8590F3'
);
});

test('should throw error when auto-detecting 42-char invalid hex address', () => {
const invalidHexAddress =
'0xgggggggggggggggggggggggggggggggggggggggg';
expect(() => getFormattedAddress(invalidHexAddress)).toThrow(
'Invalid evm address: 0xgggggggggggggggggggggggggggggggggggggggg'
);
});

test('should throw error when auto-detecting EVM address with uppercase 0X prefix', () => {
const uppercaseHexPrefix =
'0X91FD2C8D24767DB4ECE7069AA27832FFAF8590F3';
expect(() => getFormattedAddress(uppercaseHexPrefix)).toThrow(
'Invalid evm address: 0X91FD2C8D24767DB4ECE7069AA27832FFAF8590F3'
);
});
});

test('throws an error when the input is not address-like', () => {
const address = 'hello';
expect(() => getFormattedAddress(address)).toThrow();
describe('Starknet address auto-detection', () => {
test('should auto-detect and format valid unpadded Starknet address', () => {
const address =
'0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(getFormattedAddress(address)).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should auto-detect and format valid padded Starknet address', () => {
const address =
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0';
expect(getFormattedAddress(address)).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should auto-detect and format uppercase Starknet address', () => {
const address =
'0x02A0A8F3B6097E7A6BD7649DEB30715323072A159C0E6B71B689BD245C146CC0';
expect(getFormattedAddress(address)).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return padded and lowercased address when input has uppercase 0X prefix', () => {
const fullyUppercaseAddress =
'0X02A0A8F3B6097E7A6BD7649DEB30715323072A159C0E6B71B689BD245C146CC0';
expect(getFormattedAddress(fullyUppercaseAddress)).toEqual(
'0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
);
});

test('should return padded and lowercased address when given short input', () => {
const address = '0x1';
expect(getFormattedAddress(address)).toEqual(
'0x0000000000000000000000000000000000000000000000000000000000000001'
);
});

test('should auto-detect actual 41-char address as Starknet', () => {
const address = '0x123456789012345678901234567890123456789';
expect(getFormattedAddress(address)).toEqual(
'0x0000000000000000000000000123456789012345678901234567890123456789'
);
});

test('should auto-detect 43+ char address as Starknet', () => {
const address = '0x123456789012345678901234567890123456789012';
expect(getFormattedAddress(address)).toEqual(
'0x0000000000000000000000123456789012345678901234567890123456789012'
);
});
});

test('returns a padded and lowercased starknet address for any non-EVM like address input', () => {
const address = '0x1';
expect(getFormattedAddress(address)).toEqual(
'0x0000000000000000000000000000000000000000000000000000000000000001'
);
describe('Invalid address format', () => {
test('should throw error when passing invalid format argument', () => {
const validAddress = '0x91fd2c8d24767db4ece7069aa27832ffaf8590f3';
expect(() => getFormattedAddress(validAddress, 'invalid')).toThrow(
'Invalid invalid address: 0x91fd2c8d24767db4ece7069aa27832ffaf8590f3'
);
});

test('should treat undefined format parameter as auto-detection', () => {
const evmAddress = '0x91fd2c8d24767db4ece7069aa27832ffaf8590f3';
expect(getFormattedAddress(evmAddress, undefined)).toEqual(
'0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
);
});

test('should throw error when parsing invalid string', () => {
const invalidString = 'hello';
expect(() => getFormattedAddress(invalidString)).toThrow(
'Invalid address: hello'
);
});

test('should throw error when parsing empty string', () => {
const emptyString = '';
expect(() => getFormattedAddress(emptyString)).toThrow(
'Invalid address: '
);
});

test('should throw error when parsing null input', () => {
expect(() => getFormattedAddress(null)).toThrow(
'Invalid address: null'
);
});

test('should throw error when parsing undefined input', () => {
expect(() => getFormattedAddress(undefined)).toThrow(
'Invalid address: undefined'
);
});

test('should throw error when parsing number input', () => {
expect(() => getFormattedAddress(123)).toThrow(
'Invalid address: 123'
);
});

test('should throw error when parsing object input', () => {
expect(() => getFormattedAddress({})).toThrow(
'Invalid address: [object Object]'
);
});
});
});
});
Expand Down
10 changes: 6 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -830,16 +830,18 @@ export function getFormattedAddress(
address: string,
format?: 'evm' | 'starknet'
): string {
// Consider non-evm addresses as Starknet by default
// as there's no other way to differentiate them
const addressType = format ?? (isEvmAddress(address) ? 'evm' : 'starknet');
if (typeof address !== 'string' || !/^0[xX]/.test(address)) {
throw new Error(`Invalid address: ${address}`);
}

const addressType = format ?? (address.length === 42 ? 'evm' : 'starknet');

if (addressType === 'evm' && isEvmAddress(address))
return getAddress(address);
if (addressType === 'starknet' && isStarknetAddress(address))
return validateAndParseAddress(address);

throw new Error(`Invalid address: ${address}`);
throw new Error(`Invalid ${addressType} address: ${address}`);
}

function inputError(message: string) {
Expand Down