Add utility function for converting an address to checksummed string (#5067)
This commit is contained in:
5
.changeset/forty-dodos-visit.md
Normal file
5
.changeset/forty-dodos-visit.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'openzeppelin-solidity': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
`Strings`: Added a utility function for converting an address to checksummed string.
|
||||||
@ -85,6 +85,30 @@ library Strings {
|
|||||||
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
|
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
|
||||||
|
* representation, according to EIP-55.
|
||||||
|
*/
|
||||||
|
function toChecksumHexString(address addr) internal pure returns (string memory) {
|
||||||
|
bytes memory buffer = bytes(toHexString(addr));
|
||||||
|
|
||||||
|
// hash the hex part of buffer (skip length + 2 bytes, length 40)
|
||||||
|
uint256 hashValue;
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint256 i = 41; i > 1; --i) {
|
||||||
|
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
|
||||||
|
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
|
||||||
|
// case shift by xoring with 0x20
|
||||||
|
buffer[i] ^= 0x20;
|
||||||
|
}
|
||||||
|
hashValue >>= 4;
|
||||||
|
}
|
||||||
|
return string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the two strings are equal.
|
* @dev Returns true if the two strings are equal.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -108,15 +108,42 @@ describe('Strings', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toHexString address', function () {
|
describe('addresses', function () {
|
||||||
it('converts a random address', async function () {
|
const addresses = [
|
||||||
const addr = '0xa9036907dccae6a1e0033479b12e837e5cf5a02f';
|
'0xa9036907dccae6a1e0033479b12e837e5cf5a02f', // Random address
|
||||||
expect(await this.mock.getFunction('$toHexString(address)')(addr)).to.equal(addr);
|
'0x0000e0ca771e21bd00057f54a68c30d400000000', // Leading and trailing zeros
|
||||||
|
// EIP-55 reference
|
||||||
|
'0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed',
|
||||||
|
'0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359',
|
||||||
|
'0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB',
|
||||||
|
'0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb',
|
||||||
|
'0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359',
|
||||||
|
'0x52908400098527886E0F7030069857D2E4169EE7',
|
||||||
|
'0x8617E340B3D01FA5F11F306F4090FD50E238070D',
|
||||||
|
'0xde709f2102306220921060314715629080e2fb77',
|
||||||
|
'0x27b1fdb04752bbc536007a920d24acb045561c26',
|
||||||
|
'0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed',
|
||||||
|
'0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359',
|
||||||
|
'0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB',
|
||||||
|
'0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb',
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('toHexString', function () {
|
||||||
|
for (const addr of addresses) {
|
||||||
|
it(`converts ${addr}`, async function () {
|
||||||
|
expect(await this.mock.getFunction('$toHexString(address)')(addr)).to.equal(addr.toLowerCase());
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('converts an address with leading zeros', async function () {
|
describe('toChecksumHexString', function () {
|
||||||
const addr = '0x0000e0ca771e21bd00057f54a68c30d400000000';
|
for (const addr of addresses) {
|
||||||
expect(await this.mock.getFunction('$toHexString(address)')(addr)).to.equal(addr);
|
it(`converts ${addr}`, async function () {
|
||||||
|
expect(await this.mock.getFunction('$toChecksumHexString(address)')(addr)).to.equal(
|
||||||
|
ethers.getAddress(addr.toLowerCase()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user