Skip to content

Commit

Permalink
Encode using codec
Browse files Browse the repository at this point in the history
  • Loading branch information
Lbqds committed May 10, 2024
1 parent 4ff8f2f commit 6db7c62
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 36 deletions.
2 changes: 1 addition & 1 deletion packages/web3/src/codec/lockup-script-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class PublicKeyHashCodec implements Codec<PublicKeyHash> {
}

const publicKeyHashCodec = new PublicKeyHashCodec()
const publicKeyHashesCodec = new ArrayCodec(publicKeyHashCodec)
export const publicKeyHashesCodec = new ArrayCodec(publicKeyHashCodec)
const multiSigParser = Parser.start()
.nest('publicKeyHashes', { type: publicKeyHashesCodec.parser })
.nest('m', { type: compactUnsignedIntCodec.parser })
Expand Down
7 changes: 3 additions & 4 deletions packages/web3/src/utils/address.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,6 @@ describe('address', function () {
).toEqual(
'0303030f9f042a9410969f1886f85fa20f6e43176ae23fc5e64db15b3767c84c5db2dc03c83325bd2c0fe1464161c6d5f42699fc9dd799dda7f984f9fbf59b01b095be1903c0a849d8ab8633b45b45ea7f3bb3229e1083a13fd73e027aac2bc55e7f622172'
)
expect(() =>
encodeMultisigPublicKeys(Array(32).fill('030f9f042a9410969f1886f85fa20f6e43176ae23fc5e64db15b3767c84c5db2dc'), 2)
).toThrow('The length of public key array exceeds maximum limit')
})

it('should compute address from public key', () => {
Expand All @@ -183,7 +180,9 @@ describe('address', function () {
'94438313828b1b17e5d7f2c9d773d44a81af6c3ef67446fbf350497ff3b06c3741'
]
expect(() => addressFromPublicKey('0100', 'multisig')).toThrow('Invalid n in m-of-n multisig, m: 1, n: 0')
expect(() => addressFromPublicKey('0130', 'multisig')).toThrow('Invalid n in m-of-n multisig, m: 1, n: 48')
expect(() => addressFromPublicKey('013f', 'multisig')).toThrow('Invalid n in m-of-n multisig, m: 1, n: -1')
expect(() => addressFromPublicKey('0201', 'multisig')).toThrow('Invalid m in m-of-n multisig, m: 2, n: 1')
expect(() => addressFromPublicKey('3f02', 'multisig')).toThrow('Invalid m in m-of-n multisig, m: -1, n: 2')
expect(() => addressFromPublicKey('04' + encodeMultisigPublicKeys(publicKeys, 3).slice(2), 'multisig')).toThrow(
'Invalid m in m-of-n multisig, m: 4, n: 3'
)
Expand Down
67 changes: 36 additions & 31 deletions packages/web3/src/utils/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import bs58 from './bs58'
import djb2 from './djb2'
import { binToHex, hexToBinUnsafe, isHexString } from './utils'
import { KeyType } from '../signer'
import { compactSignedIntCodec } from '../codec'
import * as codec from '../codec'
import { Buffer } from 'buffer/'

const ec = new EC('secp256k1')
const PublicKeyBytesLength = 33
const MaxKeySize = 32

export enum AddressType {
P2PKH = 0x00,
Expand Down Expand Up @@ -165,44 +167,46 @@ export function addressFromPublicKey(publicKey: string, _keyType?: KeyType): str
}

function multisigAddressFromPublicKey(publicKey: string): string {
try {
const bytes = hexToBinUnsafe(publicKey)
const m = bytes[0]
const n = bytes[1]
if (n <= 0 || n >= MaxKeySize) {
throw new Error(`Invalid n in m-of-n multisig, m: ${m}, n: ${n}`)
}
if (m <= 0 || m > n) {
throw new Error(`Invalid m in m-of-n multisig, m: ${m}, n: ${n}`)
}
if (bytes.length !== PublicKeyBytesLength * n + 2) {
throw new Error('Invalid public key size')
}
if (!isHexString(publicKey)) {
throw new Error(`Invalid public key ${publicKey}, expected a hex-string`)
}
const bytes = Buffer.from(hexToBinUnsafe(publicKey))
const decodedM = compactSignedIntCodec.decode(bytes)
let index = decodedM.rest.length + 1
const decodedN = compactSignedIntCodec.decode(bytes.slice(index))
index += decodedN.rest.length + 1
const m = compactSignedIntCodec.toI32(decodedM)
const n = compactSignedIntCodec.toI32(decodedN)
if (n <= 0) {
throw new Error(`Invalid n in m-of-n multisig, m: ${m}, n: ${n}`)
}
if (m <= 0 || m > n) {
throw new Error(`Invalid m in m-of-n multisig, m: ${m}, n: ${n}`)
}
if (bytes.length !== PublicKeyBytesLength * n + 2) {
throw new Error('Invalid public key size')
}

const publicKeyHashes: Uint8Array[] = []
for (let i = 2; i < bytes.length; i += 33) {
const publicKey = bytes.slice(i, i + 33)
publicKeyHashes.push(blake.blake2b(publicKey, undefined, 32))
const publicKeyHashes: codec.lockupScript.PublicKeyHash[] = []
for (; index < bytes.length; index += 33) {
const publicKey = bytes.slice(index, index + 33)
publicKeyHashes.push({ publicKeyHash: Buffer.from(blake.blake2b(publicKey, undefined, 32)) })
}
const lockupScript: codec.lockupScript.LockupScript = {
scriptType: AddressType.P2MPKH,
script: {
publicKeyHashes: codec.lockupScript.publicKeyHashesCodec.fromArray(publicKeyHashes),
m: compactSignedIntCodec.fromI32(m)
}
const encoded = Buffer.concat([
Buffer.from([AddressType.P2MPKH]),
Buffer.from([n]),
...publicKeyHashes,
Buffer.from([m])
])
return bs58.encode(encoded)
} catch (err) {
throw new Error(`Invalid multisig public key, error: ${err}`)
}
const encoded = codec.lockupScript.lockupScriptCodec.encode(lockupScript)
return bs58.encode(encoded)
}

export function encodeMultisigPublicKeys(publicKeys: string[], m: number): string {
if (publicKeys.length === 0) {
throw new Error('Public key array is empty')
}
if (publicKeys.length >= MaxKeySize) {
throw new Error('The length of public key array exceeds maximum limit')
}
if (m <= 0 || m > publicKeys.length) {
throw new Error(`Invalid m in m-of-n multisig, m: ${m}, n: ${publicKeys.length}`)
}
Expand All @@ -211,7 +215,8 @@ export function encodeMultisigPublicKeys(publicKeys: string[], m: number): strin
throw new Error(`Invalid public key: ${publicKey}`)
}
})
return Buffer.from([m, publicKeys.length]).toString('hex') + publicKeys.join('')
const prefix = Buffer.concat([compactSignedIntCodec.encodeI32(m), compactSignedIntCodec.encodeI32(publicKeys.length)])
return prefix.toString('hex') + publicKeys.join('')
}

export function addressFromScript(script: Uint8Array): string {
Expand Down

0 comments on commit 6db7c62

Please sign in to comment.