@alephium/web3 0.2.0-rc.0 → 0.2.0-rc.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/.eslintignore +2 -2
  2. package/README.md +2 -135
  3. package/contracts/greeter/greeter.ral +3 -3
  4. package/contracts/greeter/greeter_interface.ral +1 -0
  5. package/contracts/greeter_main.ral +3 -5
  6. package/dist/alephium-web3.min.js +1 -1
  7. package/dist/alephium-web3.min.js.LICENSE.txt +0 -17
  8. package/dist/alephium-web3.min.js.map +1 -1
  9. package/dist/scripts/create-project.js +3 -2
  10. package/dist/src/api/api-alephium.d.ts +46 -13
  11. package/dist/src/api/api-alephium.js +19 -3
  12. package/dist/src/api/api-explorer.d.ts +32 -16
  13. package/dist/src/api/api-explorer.js +26 -0
  14. package/dist/src/api/index.d.ts +3 -2
  15. package/dist/src/api/index.js +22 -3
  16. package/dist/src/api/types.d.ts +23 -0
  17. package/dist/src/api/types.js +240 -0
  18. package/dist/src/contract/contract.d.ts +104 -64
  19. package/dist/src/contract/contract.js +370 -426
  20. package/dist/src/contract/events.d.ts +4 -4
  21. package/dist/src/contract/index.js +5 -1
  22. package/dist/src/contract/ralph.d.ts +4 -4
  23. package/dist/src/global.d.ts +4 -0
  24. package/dist/src/global.js +38 -0
  25. package/dist/src/index.d.ts +2 -0
  26. package/dist/src/index.js +20 -1
  27. package/dist/src/signer/index.d.ts +0 -1
  28. package/dist/src/signer/index.js +5 -2
  29. package/dist/src/signer/signer.d.ts +21 -11
  30. package/dist/src/signer/signer.js +46 -9
  31. package/dist/src/transaction/index.d.ts +0 -1
  32. package/dist/src/transaction/index.js +5 -2
  33. package/dist/src/transaction/status.d.ts +2 -1
  34. package/dist/src/utils/index.d.ts +0 -1
  35. package/dist/src/utils/index.js +5 -2
  36. package/dist/src/utils/subscription.d.ts +0 -1
  37. package/dist/src/utils/subscription.js +2 -1
  38. package/dist/src/utils/utils.d.ts +5 -4
  39. package/dist/src/utils/utils.js +18 -17
  40. package/jest-config.json +11 -0
  41. package/package.json +7 -35
  42. package/scripts/create-project.ts +3 -2
  43. package/src/api/api-alephium.ts +56 -8
  44. package/src/api/api-explorer.ts +30 -0
  45. package/src/api/index.ts +14 -3
  46. package/src/api/types.ts +233 -0
  47. package/src/contract/contract.ts +537 -526
  48. package/src/contract/events.ts +6 -6
  49. package/src/contract/ralph.ts +4 -4
  50. package/src/{transaction/sign-verify.ts → global.ts} +14 -15
  51. package/src/index.ts +3 -0
  52. package/src/signer/index.ts +0 -1
  53. package/src/signer/signer.ts +70 -19
  54. package/src/transaction/index.ts +0 -1
  55. package/src/transaction/status.ts +4 -2
  56. package/src/utils/index.ts +0 -1
  57. package/src/utils/subscription.ts +3 -3
  58. package/src/utils/utils.ts +11 -11
  59. package/templates/base/package.json +2 -2
  60. package/templates/base/src/greeter.ts +10 -9
  61. package/templates/react/package.json +2 -2
  62. package/templates/react/src/App.tsx +2 -2
  63. package/.eslintrc.json +0 -21
  64. package/LICENSE +0 -165
  65. package/contracts/add/add.ral +0 -16
  66. package/contracts/main.ral +0 -6
  67. package/contracts/sub/sub.ral +0 -9
  68. package/dist/src/signer/node-wallet.d.ts +0 -13
  69. package/dist/src/signer/node-wallet.js +0 -60
  70. package/dist/src/test/index.d.ts +0 -7
  71. package/dist/src/test/index.js +0 -41
  72. package/dist/src/test/privatekey-wallet.d.ts +0 -12
  73. package/dist/src/test/privatekey-wallet.js +0 -68
  74. package/dist/src/transaction/sign-verify.d.ts +0 -2
  75. package/dist/src/transaction/sign-verify.js +0 -58
  76. package/dist/src/utils/password-crypto.d.ts +0 -2
  77. package/dist/src/utils/password-crypto.js +0 -69
  78. package/gitignore +0 -10
  79. package/src/contract/ralph.test.ts +0 -178
  80. package/src/fixtures/address.json +0 -36
  81. package/src/fixtures/balance.json +0 -9
  82. package/src/fixtures/self-clique.json +0 -19
  83. package/src/fixtures/transaction.json +0 -13
  84. package/src/fixtures/transactions.json +0 -179
  85. package/src/signer/fixtures/genesis.json +0 -26
  86. package/src/signer/fixtures/wallets.json +0 -26
  87. package/src/signer/node-wallet.ts +0 -74
  88. package/src/test/index.ts +0 -32
  89. package/src/test/privatekey-wallet.ts +0 -58
  90. package/src/transaction/sign-verify.test.ts +0 -50
  91. package/src/utils/address.test.ts +0 -47
  92. package/src/utils/djb2.test.ts +0 -35
  93. package/src/utils/password-crypto.test.ts +0 -27
  94. package/src/utils/password-crypto.ts +0 -77
  95. package/src/utils/utils.test.ts +0 -161
  96. package/test/contract.test.ts +0 -178
  97. package/test/events.test.ts +0 -138
  98. package/test/transaction.test.ts +0 -72
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alephium/web3",
3
- "version": "0.2.0-rc.0",
3
+ "version": "0.2.0-rc.11",
4
4
  "description": "A JS/TS library to interact with the Alephium platform",
5
5
  "license": "GPL",
6
6
  "main": "dist/src/index.js",
@@ -27,29 +27,16 @@
27
27
  },
28
28
  "author": "Alephium dev <dev@alephium.org>",
29
29
  "config": {
30
- "alephium_version": "1.5.0-rc0",
31
- "explorer_backend_version": "1.7.0"
30
+ "alephium_version": "1.5.0-rc7",
31
+ "explorer_backend_version": "1.7.1"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "rm -rf dist/* && npx tsc --build . && webpack",
35
- "bundle": "webpack",
35
+ "test": "jest -i --config ./jest-config.json",
36
36
  "update-schemas": "npm run update-schema:alephium && npm run update-schema:explorer",
37
37
  "update-schema:alephium": "npx swagger-typescript-api -t ./configs -o ./src/api -n api-alephium.ts -p https://raw.githubusercontent.com/alephium/alephium/v${npm_package_config_alephium_version}/api/src/main/resources/openapi.json",
38
38
  "update-schema:explorer": "npx swagger-typescript-api -t ./configs -o ./src/api -n api-explorer.ts -p https://raw.githubusercontent.com/alephium/explorer-backend/v${npm_package_config_explorer_backend_version}/app/src/main/resources/explorer-backend-openapi.json",
39
39
  "check-versions": "node scripts/check-versions.js ${npm_package_config_alephium_version} ${npm_package_config_explorer_backend_version}",
40
- "dev": "tsnd --respawn lib/index.ts",
41
- "lint": "eslint . --ext ts",
42
- "lint:fix": "eslint . --fix --ext ts",
43
- "test": "jest -i --config ./configs/jest.config.ts",
44
- "test:client": "jest -i --config ./configs/jest-client.config.ts",
45
- "test:unit": "jest -i --config ./configs/jest-unit.config.ts",
46
- "test:watch": "npm run test -- --watch --coverage=false",
47
- "test:watch:unit": "npm run test:unit -- --watch --coverage=false",
48
- "test:watch:client": "npm run test:client -- --watch --coverage=false",
49
- "prepublishOnly": "npm run build",
50
- "prepack": "node scripts/rename-gitignore.js .gitignore gitignore",
51
- "postpack": "node scripts/rename-gitignore.js gitignore .gitignore",
52
- "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
53
40
  "start-devnet": "node scripts/start-devnet.js ${npm_package_config_alephium_version}",
54
41
  "restart-devnet": "npm run start-devnet",
55
42
  "stop-devnet": "node scripts/stop-devnet.js"
@@ -64,15 +51,12 @@
64
51
  "buffer": "^6.0.3",
65
52
  "commander": "^9.1.0",
66
53
  "cross-fetch": "^3.1.5",
67
- "crypto-js": "4.1.1",
68
- "elliptic": "6.5.4",
69
54
  "eventemitter3": "^4.0.7",
70
55
  "find-up": "^2.1.0",
71
56
  "fs-extra": "^10.0.1"
72
57
  },
73
58
  "devDependencies": {
74
- "@types/crypto-js": "^4.1.1",
75
- "@types/elliptic": "^6.4.13",
59
+ "@babel/eslint-parser": "^7.18.9",
76
60
  "@types/find-up": "^2.1.0",
77
61
  "@types/fs-extra": "^9.0.13",
78
62
  "@types/jest": "^27.5.1",
@@ -81,14 +65,12 @@
81
65
  "@types/rewire": "^2.5.28",
82
66
  "@typescript-eslint/eslint-plugin": "^4.30.0",
83
67
  "@typescript-eslint/parser": "^4.30.0",
84
- "babel-eslint": "^10.1.0",
85
68
  "clean-webpack-plugin": "4.0.0",
86
69
  "crypto-browserify": "^3.12.0",
87
70
  "eslint": "^7.32.0",
88
71
  "eslint-config-prettier": "^8.5.0",
89
72
  "eslint-plugin-header": "^3.1.1",
90
73
  "eslint-plugin-prettier": "^4.0.0",
91
- "eslint-plugin-react": "^7.29.4",
92
74
  "eslint-plugin-security": "1.4.0",
93
75
  "html-webpack-plugin": "5.5.0",
94
76
  "jest": "^28.1.0",
@@ -98,7 +80,6 @@
98
80
  "mock-socket": "^9.0.8",
99
81
  "prettier": "^2.3.2",
100
82
  "process": "^0.11.10",
101
- "react-app-rewired": "^2.2.1",
102
83
  "rewire": "^6.0.0",
103
84
  "shelljs": "^0.8.5",
104
85
  "stream-browserify": "^3.0.0",
@@ -107,21 +88,12 @@
107
88
  "ts-jest": "^28.0.2",
108
89
  "ts-node": "^10.7.0",
109
90
  "tslib": "^2.3.1",
110
- "typescript": "^4.4.2",
91
+ "typescript": "4.7.4",
111
92
  "webpack": "^5.72.0",
112
93
  "webpack-cli": "^4.9.2"
113
94
  },
114
95
  "engines": {
115
- "node": ">=14.0.0",
96
+ "node": ">=16.0.0",
116
97
  "npm": ">=7.0.0"
117
- },
118
- "prettier": {
119
- "printWidth": 120,
120
- "tabWidth": 2,
121
- "useTabs": false,
122
- "semi": false,
123
- "singleQuote": true,
124
- "bracketSameLine": false,
125
- "trailingComma": "none"
126
98
  }
127
99
  }
@@ -73,7 +73,7 @@ function prepareShared(packageRoot: string, projectRoot: string) {
73
73
  console.log('...')
74
74
 
75
75
  fsExtra.copySync(path.join(packageRoot, 'templates/shared'), projectRoot)
76
- copy('', ['.editorconfig', '.eslintignore', '.gitattributes', 'LICENSE'])
76
+ copy('', ['.editorconfig', '.eslintignore', '.gitattributes'])
77
77
  copy('dev', ['user.conf'])
78
78
  copy('scripts', ['start-devnet.js', 'stop-devnet.js'])
79
79
  if (fsExtra.existsSync(path.join(packageRoot, 'gitignore'))) {
@@ -87,7 +87,8 @@ function prepareShared(packageRoot: string, projectRoot: string) {
87
87
 
88
88
  function prepareBase(packageRoot: string, projectRoot: string) {
89
89
  prepareShared(packageRoot, projectRoot)
90
- copy('contracts', ['greeter.ral', 'greeter_interface.ral', 'greeter_main.ral'])
90
+ copy('contracts', ['greeter_main.ral'])
91
+ copy('contracts/greeter', ['greeter.ral', 'greeter_interface.ral'])
91
92
  fsExtra.copySync(path.join(packageRoot, 'templates/base'), projectRoot)
92
93
  }
93
94
 
@@ -422,6 +422,7 @@ export interface ChangeActiveAddress {
422
422
  }
423
423
 
424
424
  export interface CompileContractResult {
425
+ name: string
425
426
  bytecode: string
426
427
 
427
428
  /** @format 32-byte-hash */
@@ -429,12 +430,29 @@ export interface CompileContractResult {
429
430
  fields: FieldsSig
430
431
  functions: FunctionSig[]
431
432
  events: EventSig[]
433
+ warnings: string[]
434
+ }
435
+
436
+ export interface CompileProjectResult {
437
+ contracts: CompileContractResult[]
438
+ scripts: CompileScriptResult[]
432
439
  }
433
440
 
434
441
  export interface CompileScriptResult {
442
+ name: string
435
443
  bytecodeTemplate: string
436
444
  fields: FieldsSig
437
445
  functions: FunctionSig[]
446
+ warnings: string[]
447
+ }
448
+
449
+ export interface CompilerOptions {
450
+ ignoreUnusedConstantsWarnings?: boolean
451
+ ignoreUnusedVariablesWarnings?: boolean
452
+ ignoreUnusedFieldsWarnings?: boolean
453
+ ignoreUnusedPrivateFunctionsWarnings?: boolean
454
+ ignoreReadonlyCheckWarnings?: boolean
455
+ ignoreExternalCallCheckWarnings?: boolean
438
456
  }
439
457
 
440
458
  export interface Confirmed {
@@ -457,6 +475,7 @@ export interface Confirmed {
457
475
 
458
476
  export interface Contract {
459
477
  code: string
478
+ compilerOptions?: CompilerOptions
460
479
  }
461
480
 
462
481
  export interface ContractEvent {
@@ -561,7 +580,6 @@ export type DiscoveryAction = Reachable | Unreachable
561
580
 
562
581
  export interface EventSig {
563
582
  name: string
564
- signature: string
565
583
  fieldNames: string[]
566
584
  fieldTypes: string[]
567
585
  }
@@ -571,9 +589,9 @@ export interface FetchResponse {
571
589
  }
572
590
 
573
591
  export interface FieldsSig {
574
- signature: string
575
592
  names: string[]
576
593
  types: string[]
594
+ isMutable: boolean[]
577
595
  }
578
596
 
579
597
  export interface FixedAssetOutput {
@@ -599,9 +617,12 @@ export interface FixedAssetOutput {
599
617
 
600
618
  export interface FunctionSig {
601
619
  name: string
602
- signature: string
603
- argNames: string[]
604
- argTypes: string[]
620
+ usePreapprovedAssets: boolean
621
+ useAssetsInContract: boolean
622
+ isPublic: boolean
623
+ paramNames: string[]
624
+ paramTypes: string[]
625
+ paramIsMutable: boolean[]
605
626
  returnTypes: string[]
606
627
  }
607
628
 
@@ -703,6 +724,11 @@ export interface Penalty {
703
724
  type: string
704
725
  }
705
726
 
727
+ export interface Project {
728
+ code: string
729
+ compilerOptions?: CompilerOptions
730
+ }
731
+
706
732
  export interface Reachable {
707
733
  peers: string[]
708
734
  type: string
@@ -729,6 +755,7 @@ export interface RevealMnemonicResult {
729
755
 
730
756
  export interface Script {
731
757
  code: string
758
+ compilerOptions?: CompilerOptions
732
759
  }
733
760
 
734
761
  export interface SelfClique {
@@ -1114,7 +1141,7 @@ export enum ContentType {
1114
1141
  }
1115
1142
 
1116
1143
  export class HttpClient<SecurityDataType = unknown> {
1117
- public baseUrl: string = '{protocol}://{host}:{port}'
1144
+ public baseUrl: string = '../'
1118
1145
  private securityData: SecurityDataType | null = null
1119
1146
  private securityWorker?: ApiConfig<SecurityDataType>['securityWorker']
1120
1147
  private abortControllers = new Map<CancelToken, AbortController>()
@@ -1279,8 +1306,8 @@ export class HttpClient<SecurityDataType = unknown> {
1279
1306
 
1280
1307
  /**
1281
1308
  * @title Alephium API
1282
- * @version 1.5.0-rc0
1283
- * @baseUrl {protocol}://{host}:{port}
1309
+ * @version 1.5.0
1310
+ * @baseUrl ../
1284
1311
  */
1285
1312
  export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDataType> {
1286
1313
  wallets = {
@@ -2160,6 +2187,27 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
2160
2187
  ...params
2161
2188
  }).then(convertHttpResponse),
2162
2189
 
2190
+ /**
2191
+ * No description
2192
+ *
2193
+ * @tags Contracts
2194
+ * @name PostContractsCompileProject
2195
+ * @summary Compile a project
2196
+ * @request POST:/contracts/compile-project
2197
+ */
2198
+ postContractsCompileProject: (data: Project, params: RequestParams = {}) =>
2199
+ this.request<
2200
+ CompileProjectResult,
2201
+ BadRequest | Unauthorized | NotFound | InternalServerError | ServiceUnavailable
2202
+ >({
2203
+ path: `/contracts/compile-project`,
2204
+ method: 'POST',
2205
+ body: data,
2206
+ type: ContentType.Json,
2207
+ format: 'json',
2208
+ ...params
2209
+ }).then(convertHttpResponse),
2210
+
2163
2211
  /**
2164
2212
  * No description
2165
2213
  *
@@ -847,6 +847,36 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
847
847
  path: `/utils/sanity-check`,
848
848
  method: 'PUT',
849
849
  ...params
850
+ }).then(convertHttpResponse),
851
+
852
+ /**
853
+ * @description Update global log level, accepted: TRACE, DEBUG, INFO, WARN, ERROR
854
+ *
855
+ * @tags Utils
856
+ * @name PutUtilsUpdateGlobalLoglevel
857
+ * @request PUT:/utils/update-global-loglevel
858
+ */
859
+ putUtilsUpdateGlobalLoglevel: (data: 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR', params: RequestParams = {}) =>
860
+ this.request<void, BadRequest | Unauthorized | NotFound | InternalServerError | ServiceUnavailable>({
861
+ path: `/utils/update-global-loglevel`,
862
+ method: 'PUT',
863
+ body: data,
864
+ ...params
865
+ }).then(convertHttpResponse),
866
+
867
+ /**
868
+ * @description Update logging file, only logback.xml is accepted
869
+ *
870
+ * @tags Utils
871
+ * @name PutUtilsUpdateLogConfig
872
+ * @request PUT:/utils/update-log-config
873
+ */
874
+ putUtilsUpdateLogConfig: (data: string, params: RequestParams = {}) =>
875
+ this.request<void, BadRequest | Unauthorized | NotFound | InternalServerError | ServiceUnavailable>({
876
+ path: `/utils/update-log-config`,
877
+ method: 'PUT',
878
+ body: data,
879
+ ...params
850
880
  }).then(convertHttpResponse)
851
881
  }
852
882
  }
package/src/api/index.ts CHANGED
@@ -19,9 +19,19 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
19
19
  import { Api as NodeApi } from './api-alephium'
20
20
  import { Api as ExplorerApi } from './api-explorer'
21
21
 
22
- export class NodeProvider extends NodeApi<null> {
23
- constructor(baseUrl: string) {
24
- super({ baseUrl: baseUrl })
22
+ export class NodeProvider extends NodeApi<string> {
23
+ constructor(baseUrl: string, apiKey?: string) {
24
+ // eslint-disable-next-line security/detect-possible-timing-attacks
25
+ if (apiKey === undefined) {
26
+ super({ baseUrl: baseUrl })
27
+ } else {
28
+ super({
29
+ baseUrl: baseUrl,
30
+ baseApiParams: { secure: true },
31
+ securityWorker: (accessToken) => (accessToken !== null ? { headers: { 'X-API-KEY': `${accessToken}` } } : {})
32
+ })
33
+ this.setSecurityData(apiKey)
34
+ }
25
35
  }
26
36
  }
27
37
 
@@ -33,3 +43,4 @@ export class ExplorerProvider extends ExplorerApi<null> {
33
43
 
34
44
  export * as node from './api-alephium'
35
45
  export * as explorer from './api-explorer'
46
+ export * from './types'
@@ -0,0 +1,233 @@
1
+ /*
2
+ Copyright 2018 - 2022 The Alephium Authors
3
+ This file is part of the alephium project.
4
+
5
+ The library is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ The library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ import { assertType, bs58, Eq } from '../utils'
20
+ import * as node from './api-alephium'
21
+
22
+ export type Number256 = number | bigint | string
23
+ export type Val = Number256 | boolean | string | Val[]
24
+ export type NamedVals = Record<string, Val>
25
+
26
+ export interface Token {
27
+ id: string
28
+ amount: Number256
29
+ }
30
+ assertType<Eq<keyof Token, keyof node.Token>>
31
+
32
+ export function toApiToken(token: Token): node.Token {
33
+ return { id: token.id, amount: toApiNumber256(token.amount) }
34
+ }
35
+
36
+ export function toApiTokens(tokens?: Token[]): node.Token[] | undefined {
37
+ return tokens?.map(toApiToken)
38
+ }
39
+
40
+ export function fromApiToken(token: node.Token): Token {
41
+ return { id: token.id, amount: fromApiNumber256(token.amount) }
42
+ }
43
+
44
+ export function fromApiTokens(tokens?: node.Token[]): Token[] | undefined {
45
+ return tokens?.map(fromApiToken)
46
+ }
47
+
48
+ export function toApiBoolean(v: Val): boolean {
49
+ if (typeof v === 'boolean') {
50
+ return v
51
+ } else {
52
+ throw new Error(`Invalid boolean value: ${v}`)
53
+ }
54
+ }
55
+
56
+ // TODO: check integer bounds
57
+ export function toApiNumber256(v: Val): string {
58
+ if ((typeof v === 'number' && Number.isInteger(v)) || typeof v === 'bigint') {
59
+ return v.toString()
60
+ } else if (typeof v === 'string') {
61
+ return v
62
+ } else {
63
+ throw new Error(`Invalid 256 bit number: ${v}`)
64
+ }
65
+ }
66
+
67
+ export function toApiNumber256Optional(v?: Val): string | undefined {
68
+ return v === undefined ? undefined : toApiNumber256(v)
69
+ }
70
+
71
+ export function fromApiNumber256(n: string): Number256 {
72
+ if (Number.isSafeInteger(Number.parseInt(n))) {
73
+ return Number(n)
74
+ } else {
75
+ return BigInt(n)
76
+ }
77
+ }
78
+
79
+ // TODO: check hex string
80
+ export function toApiByteVec(v: Val): string {
81
+ if (typeof v === 'string') {
82
+ // try to convert from address to contract id
83
+ try {
84
+ const address = bs58.decode(v)
85
+ if (address.length == 33 && address[0] == 3) {
86
+ return Buffer.from(address.slice(1)).toString('hex')
87
+ }
88
+ } catch (_) {
89
+ return v as string
90
+ }
91
+ return v as string
92
+ } else {
93
+ throw new Error(`Invalid string: ${v}`)
94
+ }
95
+ }
96
+
97
+ export function toApiAddress(v: Val): string {
98
+ if (typeof v === 'string') {
99
+ try {
100
+ bs58.decode(v)
101
+ return v as string
102
+ } catch (error) {
103
+ throw new Error(`Invalid base58 string: ${v}`)
104
+ }
105
+ } else {
106
+ throw new Error(`Invalid string: ${v}`)
107
+ }
108
+ }
109
+
110
+ export function toApiArray(tpe: string, v: Val): node.Val {
111
+ if (!Array.isArray(v)) {
112
+ throw new Error(`Expected array, got ${v}`)
113
+ }
114
+
115
+ const semiColonIndex = tpe.lastIndexOf(';')
116
+ if (semiColonIndex == -1) {
117
+ throw new Error(`Invalid Val type: ${tpe}`)
118
+ }
119
+
120
+ const subType = tpe.slice(1, semiColonIndex)
121
+ const dim = parseInt(tpe.slice(semiColonIndex + 1, -1))
122
+ if ((v as Val[]).length != dim) {
123
+ throw new Error(`Invalid val dimension: ${v}`)
124
+ } else {
125
+ return { value: (v as Val[]).map((v) => toApiVal(v, subType)), type: 'Array' }
126
+ }
127
+ }
128
+
129
+ export function toApiVal(v: Val, tpe: string): node.Val {
130
+ if (tpe === 'Bool') {
131
+ return { value: toApiBoolean(v), type: tpe }
132
+ } else if (tpe === 'U256' || tpe === 'I256') {
133
+ return { value: toApiNumber256(v), type: tpe }
134
+ } else if (tpe === 'ByteVec') {
135
+ return { value: toApiByteVec(v), type: tpe }
136
+ } else if (tpe === 'Address') {
137
+ return { value: toApiAddress(v), type: tpe }
138
+ } else {
139
+ return toApiArray(tpe, v)
140
+ }
141
+ }
142
+
143
+ function _fromApiVal(vals: node.Val[], valIndex: number, tpe: string): [result: Val, nextIndex: number] {
144
+ if (vals.length === 0) {
145
+ throw new Error('Not enough Vals')
146
+ }
147
+
148
+ const firstVal = vals[`${valIndex}`]
149
+ if (tpe === 'Bool' && firstVal.type === tpe) {
150
+ return [firstVal.value as boolean, valIndex + 1]
151
+ } else if ((tpe === 'U256' || tpe === 'I256') && firstVal.type === tpe) {
152
+ return [fromApiNumber256(firstVal.value as string), valIndex + 1]
153
+ } else if ((tpe === 'ByteVec' || tpe === 'Address') && firstVal.type === tpe) {
154
+ return [firstVal.value as string, valIndex + 1]
155
+ } else {
156
+ const [baseType, dims] = decodeArrayType(tpe)
157
+ const arraySize = dims.reduce((a, b) => a * b)
158
+ const nextIndex = valIndex + arraySize
159
+ const valsToUse = vals.slice(valIndex, nextIndex)
160
+ if (valsToUse.length == arraySize && valsToUse.every((val) => val.type === baseType)) {
161
+ const localVals = valsToUse.map((val) => fromApiVal(val, baseType))
162
+ return [foldVals(localVals, dims), nextIndex]
163
+ } else {
164
+ throw new Error(`Invalid array Val type: ${valsToUse}, ${tpe}`)
165
+ }
166
+ }
167
+ }
168
+
169
+ export function fromApiVals(vals: node.Val[], names: string[], types: string[]): NamedVals {
170
+ let valIndex = 0
171
+ const result: NamedVals = {}
172
+ types.forEach((currentType, index) => {
173
+ const currentName = names[`${index}`]
174
+ const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType)
175
+ valIndex = nextIndex
176
+ result[`${currentName}`] = val
177
+ })
178
+ return result
179
+ }
180
+
181
+ export function fromApiArray(vals: node.Val[], types: string[]): Val[] {
182
+ let valIndex = 0
183
+ const result: Val[] = []
184
+ for (const currentType of types) {
185
+ const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType)
186
+ result.push(val)
187
+ valIndex = nextIndex
188
+ }
189
+ return result
190
+ }
191
+
192
+ export function fromApiVal(v: node.Val, tpe: string): Val {
193
+ if (v.type === 'Bool' && v.type === tpe) {
194
+ return v.value as boolean
195
+ } else if ((v.type === 'U256' || v.type === 'I256') && v.type === tpe) {
196
+ return fromApiNumber256(v.value as string)
197
+ } else if ((v.type === 'ByteVec' || v.type === 'Address') && v.type === tpe) {
198
+ return v.value as string
199
+ } else {
200
+ throw new Error(`Invalid node.Val type: ${v}`)
201
+ }
202
+ }
203
+
204
+ function decodeArrayType(tpe: string): [baseType: string, dims: number[]] {
205
+ const semiColonIndex = tpe.lastIndexOf(';')
206
+ if (semiColonIndex === -1) {
207
+ throw new Error(`Invalid Val type: ${tpe}`)
208
+ }
209
+
210
+ const subType = tpe.slice(1, semiColonIndex)
211
+ const dim = parseInt(tpe.slice(semiColonIndex + 1, -1))
212
+ if (subType[0] == '[') {
213
+ const [baseType, subDim] = decodeArrayType(subType)
214
+ return [baseType, (subDim.unshift(dim), subDim)]
215
+ } else {
216
+ return [subType, [dim]]
217
+ }
218
+ }
219
+
220
+ function foldVals(vals: Val[], dims: number[]): Val {
221
+ if (dims.length == 1) {
222
+ return vals
223
+ } else {
224
+ const result: Val[] = []
225
+ const chunkSize = vals.length / dims[0]
226
+ const chunkDims = dims.slice(1)
227
+ for (let i = 0; i < vals.length; i += chunkSize) {
228
+ const chunk = vals.slice(i, i + chunkSize)
229
+ result.push(foldVals(chunk, chunkDims))
230
+ }
231
+ return result
232
+ }
233
+ }