Skip to content

Commit

Permalink
feat: update methods about full address of new version
Browse files Browse the repository at this point in the history
1. import bech32, bech32m from an external pacakge
2. update format of the new full address
  • Loading branch information
Keith-CY committed Sep 29, 2021
1 parent 7e2941a commit d2e491d
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 98 deletions.
12 changes: 6 additions & 6 deletions packages/ckb-sdk-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ See [Full Doc](https://github.com/nervosnetwork/ckb-sdk-js/blob/develop/README.m
- `utils.privateKeyToAddress`: get address from private key
- `utils.pubkeyToAddress`: get address from public key
- `utils.bech32Address`: args to short/full version address
- `utils.fullPayloadToAddress`: script to full version address
- <del>`utils.fullPayloadToAddress`: script to full version address of obselete version, **deprecated and use `utils.scriptToAddress` instead**</del>
- `utils.parseAddress`: get address payload
- `utils.addressToScript`: get lock script from address
- `utils.scriptToAddress`: get full address from script
- `utils.scriptToAddress`: get full address of new version from script

- [Utils](#utils)

Expand Down Expand Up @@ -151,15 +151,15 @@ utils.addressToScript('ckb1qsvf96jqmq4483ncl7yrzfzshwchu9jd0glq4yy5r2jcsw04d7xly

```js
/**
* @description generate full version address from script, the address conforms to format type 0x00
* @description generate full address of new version from script, the address conforms to format type 0x00
* @tutorial https://github.com/nervosnetwork/rfcs/pull/239/
*/
utils.scriptToAddress({
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args":"0xb39bbc0b3673c7d36450bc14cfcdad2d559c6c64"
})
// ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqg0yp5wq
// ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdnnw7qkdnnclfkg59uzn8umtfd2kwxceqxwquc4
```

### Utils
Expand Down
81 changes: 37 additions & 44 deletions packages/ckb-sdk-utils/__tests__/address/fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@
"params": ["0x36c329ed630d6ce750712a477543672adab57f4c"],
"expected": [1, 0, 54, 195, 41, 237, 99, 13, 108, 231, 80, 113, 42, 71, 117, 67, 103, 42, 218, 181, 127, 76]
},
"should throw an error when its a full version address identified the hash_type and vm_version but code hash doesn't start with 0x":{
"params": ["0x36c329ed630d6ce750712a477543672adab57f4c", "0x00", "3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356"],
"should throw an error when its a full version address identifies the hash_type but code hash doesn't start with 0x": {
"params": [
"0x36c329ed630d6ce750712a477543672adab57f4c",
"0x00",
"3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356"
],
"exception": "'3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356' is not a valid code hash"
},
"should throw an error when its a full version address identified the hash_type and vm_version but code hash has invalid length":{
"params": ["0x36c329ed630d6ce750712a477543672adab57f4c", "0x00", "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c135"],
"should throw an error when its a full version address identifies the hash_type but code hash has invalid length": {
"params": [
"0x36c329ed630d6ce750712a477543672adab57f4c",
"0x00",
"0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c135"
],
"exception": "'0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c135' is not a valid code hash"
}
},
Expand All @@ -36,17 +44,6 @@
],
"expected": "ckt1qsvf96jqmq4483ncl7yrzfzshwchu9jd0glq4yy5r2jcsw04d7xlydkr98kkxrtvuag8z2j8w4pkw2k6k4l5c02auef"
},
"data1 hash type":{
"params": [
{
"args": "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101",
"type": "0x00",
"prefix": "ckt",
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356"
}
],
"expected": "ckt1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqsqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqg8gw2zh"
},
"default type = 0x02 and default prefix = ckb": {
"params": [
{
Expand Down Expand Up @@ -131,8 +128,10 @@
"params": ["ckb1qsvf96jqmq4483ncl7yrzfzshwchu9jd0glq4yy5r2jcsw04d7xlydkr98kkxrtvuag8z2j8w4pkw2k6k4l5czfy37k"],
"expected": [4, 24, 146, 234, 64, 216, 43, 83, 198, 120, 255, 136, 49, 36, 80, 187, 177, 126, 22, 77, 122, 62, 10, 144, 148, 26, 165, 136, 57, 245, 111, 141, 242, 54, 195, 41, 237, 99, 13, 108, 231, 80, 113, 42, 71, 117, 67, 103, 42, 218, 181, 127, 76 ]
},
"full version address identified the hash_type and vm_version": {
"params": ["ckt1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgutrqyp"],
"full version address identifies the hash_type": {
"params": [
"ckt1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgutrqyp"
],
"expected": [0, 52, 25, 161, 192, 158, 178, 86, 127, 101, 82, 238, 122, 142, 207, 253, 100, 21, 92, 255, 224, 241, 121, 110, 110, 97, 236, 8, 141, 116, 12, 19, 86, 1, 0, 23, 79, 178, 190, 46, 93, 12, 26, 59, 134, 148, 248, 50, 53, 10, 51, 193, 104, 93, 71, 122, 12, 1, 1]
},
"should throw an error when short version address has invalid payload size": {
Expand All @@ -159,21 +158,15 @@
"params": ["ckb1qsqcjt4ypkpt20r83lugxyj9pwa30cty6737p2gfgx493qul2cgvrxhw"],
"exception": "'ckb1qsqcjt4ypkpt20r83lugxyj9pwa30cty6737p2gfgx493qul2cgvrxhw' is not a valid full version address"
},
"should throw an error when full version address identified the hash_type and vm_version has invalid code hash": {
"should throw an error when full version address identifies the hash_type has invalid code hash": {
"params": ["ckb1qqv6rsy7kft87e2jaeaganlavs24ellq79ukumnpasyg6aqvzdtqzukxep"],
"exception": "'ckb1qqv6rsy7kft87e2jaeaganlavs24ellq79ukumnpasyg6aqvzdtqzukxep' is not a valid address"
},
"should throw an error when full version address identified the hash_type and vm_version has invalid hash type": {
"params": ["ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqcqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgaxsc2r"],
"should throw an error when full version address identifies the hash_type has invalid hash type": {
"params": [
"ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqcqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgaxsc2r"
],
"exception": "'ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqcqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgaxsc2r' is not a valid address"
},
"should throw an error when full version address identified the hash_type and vm_version has invalid args length": {
"params": ["ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqghy4uyeq"],
"exception": "'ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqghy4uyeq' is not a valid address"
},
"should throw an error when full version address identified the hash_type and vm_version has args not matching args len": {
"params": ["ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqz7etutjapsdrhp55lqer2z3nc95963m6psqszx2kx5s"],
"exception": "'ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqz7etutjapsdrhp55lqer2z3nc95963m6psqszx2kx5s' is not a valid address"
}
},
"addressToScript": {
Expand Down Expand Up @@ -225,43 +218,43 @@
"args": "0x36c329ed630d6ce750712a477543672adab57f4c"
}
},
"full version address identified the hash_type and vm_version": {
"params": ["ckt1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgutrqyp"],
"full version address identifies the hash_type": {
"params": ["ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdnnw7qkdnnclfkg59uzn8umtfd2kwxceqxwquc4"],
"expected": {
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "0xb39bbc0b3673c7d36450bc14cfcdad2d559c6c64"
}
}
},
"scriptToAddress": {
"full version mainnet address identified the hash_type and vm_version": {
"full version mainnet address identifies the hash_type": {
"params": [
{
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "0xb39bbc0b3673c7d36450bc14cfcdad2d559c6c64"
}
],
"expected": "ckb1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqg0yp5wq"
"expected": "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdnnw7qkdnnclfkg59uzn8umtfd2kwxceqxwquc4"
},
"full version testnet address identified the hash_type and vm_version": {
"full version testnet address identifies the hash_type": {
"params": [
{
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "0xb39bbc0b3673c7d36450bc14cfcdad2d559c6c64"
},
false
],
"expected": "ckt1qq6pngwqn6e9vlm92th84rk0l4jp2h8lurchjmnwv8kq3rt5psf4vqgqza8m903wt5xp5wuxjnurydg2x0qksh280gxqzqgutrqyp"
"expected": "ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdnnw7qkdnnclfkg59uzn8umtfd2kwxceqgutnjd"
},
"should throw an error when args doesn't start with 0x": {
"params": [
{
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"hashType": "type",
"args":"4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
}
],
"exception": "Hex string 4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101 should start with 0x"
Expand All @@ -271,7 +264,7 @@
{
"codeHash": "3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"hashType": "type",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
}
],
"exception": "'3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356' is not a valid code hash"
Expand All @@ -281,7 +274,7 @@
{
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c135",
"hashType": "type",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
}
],
"exception": "'0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c135' is not a valid code hash"
Expand All @@ -291,7 +284,7 @@
{
"codeHash": "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"hashType": "type1",
"args":"0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
"args": "0x4fb2be2e5d0c1a3b8694f832350a33c1685d477a0c0101"
}
],
"exception": "'type1' is not a valid hash type"
Expand Down
7 changes: 0 additions & 7 deletions packages/ckb-sdk-utils/__tests__/exceptions/fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,6 @@
"message": "'0x03' is not a valid hash type"
}
},
"ArgsLenException": {
"params": [""],
"expected": {
"code": 104,
"message": "'' is not a valid args length"
}
},
"OutLenTooSmallException": {
"params": [16, 32],
"expected": {
Expand Down
1 change: 1 addition & 0 deletions packages/ckb-sdk-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
},
"dependencies": {
"@nervosnetwork/ckb-types": "0.43.0",
"bech32": "2.0.0",
"elliptic": "6.5.4",
"jsbi": "3.1.3",
"tslib": "2.3.1"
Expand Down
65 changes: 35 additions & 30 deletions packages/ckb-sdk-utils/src/address/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { bech32, blake160 } from '..'
import { blake160, bech32, bech32m } from '..'
import {
SECP256K1_BLAKE160,
SECP256K1_MULTISIG,
Expand All @@ -12,9 +12,10 @@ import {
AddressPayloadException,
CodeHashException,
HashTypeException,
ArgsLenException,
} from '../exceptions'

const MAX_BECH32_LIMIT = 1023

// TODO: deprecate outdated methods

export enum AddressPrefix {
Expand All @@ -23,22 +24,19 @@ export enum AddressPrefix {
}

export enum AddressType {
FullVersion = '0x00', // full version identified the hash_type and vm_version
FullVersion = '0x00', // full version identifies the hash_type
HashIdx = '0x01', // short version for locks with popular codehash
DataCodeHash = '0x02', // full version with hash type 'Data', deprecated
TypeCodeHash = '0x04', // full version with hash type 'Type', deprecated
}

/**
* @description payload to a full address of new version
*/
const payloadToAddress = (payload: Uint8Array, isMainnet = true) =>
bech32.encode(isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, bech32.toWords(payload))
bech32m.encode(isMainnet ? AddressPrefix.Mainnet : AddressPrefix.Testnet, bech32.toWords(payload), MAX_BECH32_LIMIT)

const scriptToPayload = ({ codeHash, hashType, args }: CKBComponents.Script): Uint8Array => {
enum HashType {
data = '00',
type = '01',
data1 = '02',
}

if (!args.startsWith('0x')) {
throw new HexStringWithout0xException(args)
}
Expand All @@ -47,16 +45,26 @@ const scriptToPayload = ({ codeHash, hashType, args }: CKBComponents.Script): Ui
throw new CodeHashException(codeHash)
}

enum HashType {
data = '00',
type = '01',
data1 = '02',
}

if (!HashType[hashType]) {
throw new HashTypeException(hashType)
}
const argsLen = args.length / 2 - 1

return hexToBytes(
`0x00${codeHash.slice(2)}${HashType[hashType]}${argsLen.toString(16).padStart(4, '0')}${args.slice(2)}`,
)
return hexToBytes(`0x00${codeHash.slice(2)}${HashType[hashType]}${args.slice(2)}`)
}

/**
* @function scriptToAddress
* @description The only way recommended to generated a full address of new version
* @param {object} script
* @param {booealn} isMainnet
* @returns {string} address
*/
export const scriptToAddress = (script: CKBComponents.Script, isMainnet = true) =>
payloadToAddress(scriptToPayload(script), isMainnet)

Expand Down Expand Up @@ -117,7 +125,7 @@ export const toAddressPayload = (
}

/**
* @name bech32Address
* @function bech32Address
* @description generate the address by bech32 algorithm
* @param args, used as the identifier of an address, usually the public key hash is used.
* @param {[string]} prefix, the prefix precedes the address, default to be ckb.
Expand All @@ -128,11 +136,12 @@ export const toAddressPayload = (
export const bech32Address = (
args: Uint8Array | string,
{ prefix = AddressPrefix.Mainnet, type = AddressType.HashIdx, codeHashOrCodeHashIndex = '0x00' }: AddressOptions = {},
) => bech32.encode(prefix, bech32.toWords(toAddressPayload(args, type, codeHashOrCodeHashIndex)))
) => bech32.encode(prefix, bech32.toWords(toAddressPayload(args, type, codeHashOrCodeHashIndex)), MAX_BECH32_LIMIT)

/**
* @deprecated
* @name fullPayloadToAddress
* @description generate the address with payload in full version format.
* @description deprecated method to generate the address with payload in full version format. Use scriptToAddress instead.
* @param {string} args, used as the identifier of an address.
* @param {[string]} prefix, the prefix precedes the address, default to be ckb.
* @param {[string]} type, used to indicate which format the address conforms to, default to be 0x02,
Expand Down Expand Up @@ -209,15 +218,6 @@ const isPayloadValid = (payload: Uint8Array) => {
throw new HashTypeException(`0x${hashType.toString(16)}`)
}

const argsLen = data.slice(33, 35)
if (argsLen.length < 2) {
throw new ArgsLenException(bytesToHex(argsLen))
}

if (data.slice(35).length !== +bytesToHex(argsLen)) {
throw new ArgsLenException(bytesToHex(argsLen))
}

break
}
default: {
Expand All @@ -238,8 +238,14 @@ export declare interface ParseAddress {
* e.g. 0x | 01 | 00 | e2fa82e70b062c8644b80ad7ecf6e015e5f352f6
*/
export const parseAddress: ParseAddress = (address: string, encode: 'binary' | 'hex' = 'binary'): any => {
const decoded = bech32.decode(address)
const payload = bech32.fromWords(new Uint8Array(decoded.words))
let payload: Uint8Array = new Uint8Array()
try {
const decoded = bech32.decode(address, MAX_BECH32_LIMIT)
payload = new Uint8Array(bech32.fromWords(new Uint8Array(decoded.words)))
} catch {
const decoded = bech32m.decode(address, MAX_BECH32_LIMIT)
payload = new Uint8Array(bech32m.fromWords(new Uint8Array(decoded.words)))
}
try {
isPayloadValid(payload)
} catch (err) {
Expand All @@ -262,8 +268,7 @@ export const addressToScript = (address: string): CKBComponents.Script => {

const codeHash = `0x${p.substr(4, 64)}`
const hashType = HASH_TYPE[p.substr(68, 2)]
const argLen = parseInt(p.substr(70, 4), 16)
const args = `0x${p.substr(74, argLen * 2)}`
const args = `0x${p.substr(70)}`
return { codeHash, hashType, args }
}

Expand Down
4 changes: 3 additions & 1 deletion packages/ckb-sdk-utils/src/crypto/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { bech32, bech32m } from 'bech32'
import blake2b from './blake2b'
import bech32 from './bech32'
import blake160 from './blake160'

module.exports = {
blake2b,
blake160,
bech32,
bech32m,
}

export default {
blake2b,
blake160,
bech32,
bech32m,
}
Loading

0 comments on commit d2e491d

Please sign in to comment.