Last active
June 6, 2025 21:20
-
-
Save Amxx/ea6f262da365e81f799cfdc3994cb98c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
const { ethers } = require('ethers'); | |
// see https://github.com/ChainAgnostic/namespaces/pull/140 | |
const CAIP350 = Object.fromEntries(Object.entries({ | |
eip155: '0x0000', | |
solana: '0x0002', | |
}).flatMap(([k,v]) => [[k,v],[v,k]])); | |
const ENCODERS = { | |
eip155: { reference: x => ethers.toBigInt(x).toString(), address: ethers.hexlify }, | |
solana: { reference: ethers.encodeBase58, address: ethers.encodeBase58 }, | |
} | |
const decode = value => { | |
if (value === undefined || value === null || value === '') return '0x'; | |
try { | |
return ethers.toBeHex(value) | |
} catch {} | |
try { | |
return ethers.toBeHex(ethers.decodeBase58(value)); | |
} catch {} | |
try { | |
return ethers.toBeHex(ethers.decodeBase64(value)); | |
} catch {} | |
throw new Error(`Unable to decode ${value}`) | |
} | |
const formatERC7913v1 = ({ type, reference, address }) => { | |
const chainReferenceHex = decode(reference); | |
const addressHex = decode(address); | |
const interoperableAddress = ethers.solidityPacked([ | |
'uint16', // version | |
'uint16', // type | |
'uint8', // chainReferenceLength | |
'bytes', // chainReference | |
'uint8', // addressLength | |
'bytes', // address | |
], [ | |
1n, | |
CAIP350[type], | |
ethers.getBytes(chainReferenceHex).length, | |
chainReferenceHex, | |
ethers.getBytes(addressHex).length, | |
addressHex | |
]); | |
const checksum = ethers.keccak256(ethers.getBytes(interoperableAddress).slice(2)).slice(2, 10).toUpperCase(); | |
const interoperableName = [ address, '@', type, reference && `:${reference}`, '#', checksum ].filter(Boolean).join(''); | |
return { address : interoperableAddress, name: interoperableName, checksum }; | |
} | |
const parseERC7913v1 = input => { | |
const parse = input.match(/(?<address>[.-:_%a-zA-Z0-9]*)@(?<chain>[.-:_a-zA-Z0-9]*)#(?<checksum>[0-9A-F]{8})/); | |
if (parse) { | |
const { address, chain, checksum } = parse.groups; | |
const [ type, reference ] = chain.split(/:(.*)/s); | |
const entry = { type, reference: reference || undefined, address: address || undefined }; | |
return formatERC7913v1(entry).checksum === checksum | |
? entry | |
: null; | |
} else if (ethers.isBytesLike(input)) { | |
const buffer = ethers.getBytes(input); | |
if (ethers.toBigInt(buffer.slice(0, 2)) !== 1n) throw new Error('only version 1 is supported'); | |
const type = CAIP350[ethers.hexlify(buffer.slice(2,4))]; | |
const referenceLength = buffer[4]; | |
const reference = referenceLength ? ENCODERS[type].reference(buffer.slice(5,5+referenceLength)) : undefined; | |
const addressLength = buffer[5+referenceLength]; | |
const address = addressLength ? ENCODERS[type].address(buffer.slice(6+referenceLength,6+referenceLength+addressLength)) : undefined; | |
return buffer.length >= 6+referenceLength+addressLength | |
? { type, reference, address } | |
: null; | |
} else { | |
return null; | |
} | |
} | |
// Examples | |
[ | |
{ | |
type: 'eip155', | |
reference: '1', | |
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', | |
}, | |
{ | |
type: 'solana', | |
reference: '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d', | |
address: 'MJKqp326RZCHnAAbew9MDdui3iCKWco7fsK9sVuZTX2', | |
}, | |
{ | |
type: 'eip155', | |
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', | |
}, | |
{ | |
type: 'solana', | |
reference: '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d', | |
}, | |
{ | |
type: 'eip155', | |
reference: '42161', | |
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', | |
}, | |
].forEach(entry => { | |
console.log('=========================================================') | |
console.log(formatERC7913v1(entry)) | |
console.log(parseERC7913v1(formatERC7913v1(entry).address)) | |
console.log(parseERC7913v1(formatERC7913v1(entry).name)) | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment