wharfkit / antelope

Core types, client interfaces, and other tools for working with Antelope-based blockchains.
Other
44 stars 23 forks source link

Using `esnext` as target breaks some decoding #76

Closed aaroncox closed 3 months ago

aaroncox commented 1 year ago

Just stumbled into this in a nodejs project, when setting "target": "esnext" in the tsconfig.json, it prevents some structs from rendering properly.

Sample code:

const sample =
    '80b1915e5d268dca000000000090b1ca01000000403290b1ca00000000a8ed3232e2e1006500000000000000000000017055cb2a5fd5b2ca000000572d3ccdcd01000000403290b1ca00000000a8ed32322a000000403290b1ca00000092019ca65e010000000000000004555344540000000954657374206d73696700'

@Struct.type('propose')
class Propose extends Struct {
    @Struct.field(Name) proposer!: Name
    @Struct.field(Name) proposal_name!: Name
    @Struct.field(PermissionLevel, {array: true}) requested!: PermissionLevel[]
    @Struct.field(Transaction) trx!: Transaction
}

const broken = Serializer.decode({
    data: sample,
    type: Propose,
})

console.log(broken)

This causes the output to be:

Propose {
  proposer: undefined,
  proposal_name: undefined,
  requested: undefined,
  trx: undefined
}

However when I switch to using "target": "es2020", the same code above outputs:

Propose {
  proposer: Name { value: UInt64 { value: [BN] } },
  proposal_name: Name { value: UInt64 { value: [BN] } },
  requested: [ PermissionLevel { actor: [Name], permission: [Name] } ],
  trx: Transaction {
    expiration: TimePointSec { value: [UInt32] },
    ref_block_num: UInt16 { value: [BN] },
    ref_block_prefix: UInt32 { value: [BN] },
    max_net_usage_words: VarUInt { value: [BN] },
    max_cpu_usage_ms: UInt8 { value: [BN] },
    delay_sec: VarUInt { value: [BN] },
    context_free_actions: [],
    actions: [ [Action] ],
    transaction_extensions: []
  }
}

Not sure what in esnext breaks this, and not sure if we need to fix - but recording here for sake of jotting it down somewhere.

aaroncox commented 1 year ago

More information, since I ran into it again.

marc0olo commented 9 months ago

I faced a similar issue when exploring the usage of a via CLI generated contract file in an example app included in the wharfkit-wallet-plugin-template where following tsconfig.json is used:

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    "experimentalDecorators": true,
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

the tsconfig.node.json is:

{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}

I generated the contract for atomicmarket with CLI version 2.6.3 and I try to fetch the market balances as follows:

import { APIClient as AntelopeAPIClient } from '@wharfkit/antelope'
import { Contract as AtomicMarketContract } from "./atomicmarket"

const antelopeClient = new AntelopeAPIClient({ url: "https://proton.eosusa.io" })
const amContract = new AtomicMarketContract({client: antelopeClient, account: 'atomicmarket'})
const userBalance = await amContract.table('balances').get(session!.actor.toString())

console.log(userBalance)

the output of (an existing balance row) is:

balances_s {owner: undefined, quantities: undefined}
dallasjohnson commented 8 months ago

I was able to get it working with es2022 but I also saw failures with "useDefineForClassFields": true and I needed to explicitly set it to false "useDefineForClassFields": false since the base tsconfig sets that property to true.

aaroncox commented 4 months ago

I think I figured this out - it's the outputted struct classes and incompatibility with useDefineForClassFields.

Take for example this struct:

@Struct.type('propose')
class Propose extends Struct {
    @Struct.field(Name) proposer!: Name
}

With useDefineForClassFields: true this is going to return undefined as the values.

However, if you change the struct to the format below, the values now populate correctly.

@Struct.type('propose')
class Propose extends Struct {
    @Struct.field(Name) declare proposer: Name
}

It's prepending the property name with declare and removing the ! after it.

Any already generated structs will need to be modified to include this change.

We'll update our libraries and make the command line tools use this syntax.

aaroncox commented 3 months ago

The wharfkit/cli toolkit now uses the new syntax as described above. I think we can finally close this one out.

If there's any instances of this still happening - feel free to reopen the issue.