Skip to content
Open
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
4 changes: 2 additions & 2 deletions ur-packages/coin-identity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ secp256k1=8 ; SECG secp256k1 curve IESG
elliptic_curve = P256 / P384 / P521 / X25519 / X448 / Ed25519 / Ed448 / secp256k1

; Subtypes specific to some coins (e.g. ChainId for EVM chains)
hex_string = #6.263(bstr) ; byte string is a hexadecimal string no need for decoding
sub_type_exp = uint32 / str / hex_string
hex-string = #6.263(bstr) ; IANA tag 263 — bytes read as a hexadecimal string, no decoding
sub_type_exp = uint32 / str / hex-string

coin-identity = {
curve: elliptic_curve,
Expand Down
10 changes: 5 additions & 5 deletions ur-packages/coin-identity/src/CoinIdentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@
elliptic_curve = P256 / P384 / P521 / X25519 / X448 / Ed25519 / Ed448 / secp256k1

; Subtypes specific to some coins (e.g. ChainId for EVM chains)
hex_string = #6.263(bstr) ; byte string is a hexadecimal string no need for decoding
sub_type_exp = uint32 / str / hex_string
hex-string = #6.263(bstr) ; IANA tag 263 — bytes read as a hexadecimal string, no decoding
sub_type_exp = uint32 / str / hex-string

coin-identity = {
curve: elliptic_curve,
Expand Down Expand Up @@ -102,9 +102,9 @@
*
* elliptic_curve = P256 / P384 / P521 / X25519 / X448 / Ed25519 / Ed448 / secp256k1
*
* ; Subtypes specific to some coins (e.g. ChainId for EVM chains)
* hex_string = #6.263(bstr) ; byte string is a hexadecimal string no need for decoding
* sub_type_exp = uint32 / str / hex_string
* ; Subtypes specific to some coins (e.g. ChainId for EVM chains)
* hex-string = #6.263(bstr) ; IANA tag 263 — bytes read as a hexadecimal string, no decoding
* sub_type_exp = uint32 / str / hex-string
*
* coin-identity = {
* curve: elliptic_curve,
Expand Down Expand Up @@ -134,7 +134,7 @@
const { curve, type, subtype } = data

// Return an instance of the generated class
return new this(curve, type, subtype)

Check failure on line 137 in ur-packages/coin-identity/src/CoinIdentity.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe argument of type `any` assigned to a parameter of type `sub_type_exp[] | undefined`

Check failure on line 137 in ur-packages/coin-identity/src/CoinIdentity.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe argument of type `any` assigned to a parameter of type `number`

Check failure on line 137 in ur-packages/coin-identity/src/CoinIdentity.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe argument of type `any` assigned to a parameter of type `EllipticCurve`
}

public getCurve = () => this.data.curve
Expand Down
3 changes: 1 addition & 2 deletions ur-packages/hex-string/src/HexString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ const HexStringBase: RegistryItemClass = registryItemFactory({
tag: 263,
URType: 'hex-string',
CDDL: `
hexadecimal-tag = #6.263(hex-bytes)
hex-bytes = bytes
hex-string = #6.263(bstr)
`,
})

Expand Down
2 changes: 1 addition & 1 deletion ur-packages/hex-string/src/addToRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UrRegistry } from '@ngraveio/bc-ur'
import { HexString } from './HexString'

// Add hexstring to the global registry
// Add hex-string to the global registry
UrRegistry.addItemOnce(HexString);
38 changes: 22 additions & 16 deletions ur-packages/multi-layer-sync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ import { DetailedAccount, PortfolioCoin, PortfolioMetadata, Portfolio } from '@n

The `DetailedAccount` class represents an account with detailed information, including the HDKey and optional token IDs.

Token IDs that are canonically hexadecimal (e.g. EVM ERC20 contract addresses) are encoded using [CBOR tag 263 (hex-string)](https://github.com/toravir/CBOR-Tag-Specs/blob/master/hexString.md) to halve the on-wire size versus the equivalent `0x…` text. All other identifiers — including compound ids for ERC721/ERC1155 and SPL mint addresses — are encoded as plain text strings (`tstr`), following the UAI `tokenid[.subtype…]` convention from [NBCR-2024-001](https://github.com/ngraveio/Research/blob/main/papers/nbcr-2024-001-unique-asset-id.md).

```mermaid
flowchart TB
subgraph DetailedAccount
Expand All @@ -88,30 +90,34 @@ flowchart TB
**CDDL Definition:**
```CDDL
account_exp = #6.40303(hdkey) / #6.40308(output-descriptor)
hex-string = #6.263(bstr)

; Accounts are specified using either '#6.40303(hdkey)' or
; Accounts are specified using either '#6.40303(hdkey)' or
; '#6.40308(output-descriptor)'.
; By default, '#6.40303(hdkey)' should be used to share public keys and
; extended public keys.
; '#6.308(output-descriptor)' should be used to share an output descriptor,
; '#6.40308(output-descriptor)' should be used to share an output descriptor,
; e.g. for the different Bitcoin address formats (P2PKH, P2SH-P2WPKH, P2WPKH, P2TR).
;
; 'hex-string' (IANA tag 263) wraps bytes meant to be read as a hexadecimal
; string — the tag preserves hex semantics for display and comparison.

; Optional 'token-ids' to indicate the synchronization of a list of tokens with
; the associated accounts
; 'token-id' is defined differently depending on the blockchain:
; - ERC20 tokens on EVM chains are identified by their contract addresses
; (e.g. `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`)
; - ERC1155 tokens are identifed with their contract addresses followed by their
; ID with ':' as separator (e.g. `0xfaafdc07907ff5120a76b34b731b278c38d6043c:
; 508851954656174721695133294256171964208`)
; - ESDT tokens on MultiversX are by their name followed by their ID with `-` as
; separator (e.g. `USDC-c76f1f`)
; - SPL tokens on Solana are identified by their contract addresses
; (e.g. `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`)

detailed-account = {
; the associated accounts.
; 'token-id' encoding follows the Unique Asset Identifier (UAI) convention —
; see NBCR-2024-001. A token-id is either a scalar identifier or a compound
; "parent.subtype[.subtype...]" form. Current encodings per blockchain:
; - ERC20 tokens on EVM chains are identified by their contract addresses,
; encoded as 'hex-string' (e.g. `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`).
; - ERC721 / ERC1155 tokens are identified by contract address plus token id,
; encoded as tstr using the UAI "contract.tokenId" form (e.g.
; `0xfaafdc07907ff5120a76b34b731b278c38d6043c.508851954656174721695133294256171964208`).
; - SPL / Token-2022 on Solana are identified by their mint address,
; encoded as tstr (e.g. `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`).

detailed-account = {
account: account_exp,
? token-ids: [+ string / bytes] ; Specify multiple tokens associated to one account
? token-ids: [+ tstr / hex-string] ; Specify multiple tokens associated to one account
}

account = 1
Expand Down
55 changes: 27 additions & 28 deletions ur-packages/multi-layer-sync/src/DetailedAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,38 @@
allowKeysNotInMap: false,
CDDL: `
account_exp = #6.40303(hdkey) / #6.40308(output-descriptor)
hex-string = #6.263(bstr)

; Accounts are specified using either '#6.40303(hdkey)' or
; Accounts are specified using either '#6.40303(hdkey)' or
; '#6.40308(output-descriptor)'.
; By default, '#6.40303(hdkey)' should be used to share public keys and
; extended public keys.
; '#6.308(output-descriptor)' should be used to share an output descriptor,
; '#6.40308(output-descriptor)' should be used to share an output descriptor,
; e.g. for the different Bitcoin address formats (P2PKH, P2SH-P2WPKH, P2WPKH, P2TR).
;
; 'hex-string' (IANA tag 263) wraps bytes meant to be read as a hexadecimal
; string — the tag preserves hex semantics for display and comparison.

; Optional 'token-ids' to indicate the synchronization of a list of tokens with
; the associated accounts
; 'token-id' is defined differently depending on the blockchain:
; - ERC20 tokens on EVM chains are identified by their contract addresses
; (e.g. "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
; - ERC1155 tokens are identifed with their contract addresses followed by their
; ID with ':' as separator (e.g. "0xfaafdc07907ff5120a76b34b731b278c38d6043c:
; 508851954656174721695133294256171964208")
; - ESDT tokens on MultiversX are by their name followed by their ID with "-" as
; separator (e.g. "USDC-c76f1f")
; - SPL tokens on Solana are identified by their contract addresses
; (e.g. "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")

detailed-account = {
; the associated accounts.
; 'token-id' encoding follows the Unique Asset Identifier (UAI) convention —
; see NBCR-2024-001. A token-id is either a scalar identifier or a compound
; "parent.subtype[.subtype...]" form. Current encodings per blockchain:
; - ERC20 tokens on EVM chains are identified by their contract addresses,
; encoded as 'hex-string' (e.g. "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").
; - ERC721 / ERC1155 tokens are identified by contract address plus token id,
; encoded as tstr using the UAI "contract.tokenId" form (e.g.
; "0xfaafdc07907ff5120a76b34b731b278c38d6043c.508851954656174721695133294256171964208").
; - SPL / Token-2022 on Solana are identified by their mint address,
; encoded as tstr (e.g. "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v").

detailed-account = {
account: account_exp,
? token-ids: [+ string / bytes] ; Specify multiple tokens associated to one account
? token-ids: [+ tstr / hex-string] ; Specify multiple tokens associated to one account
}

account = 1
token-ids = 2
token-ids = 2
`,
}) {
data: {
Expand All @@ -55,25 +59,21 @@
}

constructor(data: IDetailAccountInput) {
// Token Ids are just hex string for erc20 token like 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
// For ESDT and SPL types its going to be encoded as string
// We will try to parse the string into bytes with removing 0x part,
// if we cannot we will encode it as utf8 string
// Promote hex-shaped inputs to HexString so they serialise as #6.263(bstr);
// other strings stay tstr.
super(data)
//@ts-ignore
this.data = data

let tokenIds = data.tokenIds

// If token ids are provided, convert them to hex strings
if (tokenIds !== undefined && Array.isArray(data.tokenIds)) {
// Try to parse them into hex strings
// Try each id as hex; already-HexString passes through, non-hex input
// throws and falls back to tstr.
tokenIds = tokenIds.map(tokenId => {
// If its already hexstring, return it
if (tokenId instanceof HexString) return tokenId as HexString
// If its buffer or a string try to parse as HexString
if (tokenId instanceof HexString) return tokenId
try {
return new HexString(tokenId)

Check failure on line 76 in ur-packages/multi-layer-sync/src/DetailedAccount.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe construction of an any type value
} catch (error) {
/* no-op */
return tokenId as string
Expand Down Expand Up @@ -126,14 +126,13 @@
public getOutputDescriptor = () => {
return this.data.account instanceof OutputDescriptor ? this.data.account : undefined
}
/** Hex-encoded token ids are rendered with a `0x` prefix for round-trip parity. */
public getTokenIds = () => {
if (!this.data.tokenIds) return undefined

// Always return string representation of the token ids
return this.data.tokenIds.map((tokenId: HexString | string) => {
if (tokenId instanceof HexString) {
// Shall we really add 0x to start?
return '0x' + tokenId.getData()

Check failure on line 135 in ur-packages/multi-layer-sync/src/DetailedAccount.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe call of an `any` typed value

Check failure on line 135 in ur-packages/multi-layer-sync/src/DetailedAccount.ts

View workflow job for this annotation

GitHub Actions / Lint

Invalid operand for a '+' operation. Operands must each be a number or string. Got `any`
}
return tokenId
})
Expand Down Expand Up @@ -169,7 +168,7 @@
}

static checkHdKey(hdKey: HDKey) {
const origin = hdKey.getOrigin()

Check failure on line 171 in ur-packages/multi-layer-sync/src/DetailedAccount.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe call of an `any` typed value

if (origin == undefined) {
throw new Error('HDKey must have origin')
Expand All @@ -180,7 +179,7 @@
// Eg: m/44'/60'/0
// The other path components are not allowed
// Eg: m/44/*/1-5
if (!origin.isOnlySimple()) {

Check failure on line 182 in ur-packages/multi-layer-sync/src/DetailedAccount.ts

View workflow job for this annotation

GitHub Actions / Lint

Unsafe call of an `any` typed value
throw new Error('Detailed account path can only contain index components')
}

Expand Down
Loading