@alephium/web3 1.11.6 → 1.12.0-beta.0

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 (35) hide show
  1. package/dist/alephium-web3.min.js +1 -1
  2. package/dist/alephium-web3.min.js.map +1 -1
  3. package/dist/src/address/address.d.ts +11 -1
  4. package/dist/src/address/address.js +117 -11
  5. package/dist/src/api/api-alephium.d.ts +80 -0
  6. package/dist/src/api/api-alephium.js +50 -0
  7. package/dist/src/api/node-provider.d.ts +2 -0
  8. package/dist/src/api/node-provider.js +1 -0
  9. package/dist/src/api/types.d.ts +1 -1
  10. package/dist/src/api/types.js +10 -5
  11. package/dist/src/codec/lockup-script-codec.d.ts +11 -2
  12. package/dist/src/codec/lockup-script-codec.js +8 -1
  13. package/dist/src/codec/unlock-script-codec.d.ts +11 -3
  14. package/dist/src/codec/unlock-script-codec.js +14 -4
  15. package/dist/src/contract/contract.d.ts +3 -3
  16. package/dist/src/contract/contract.js +12 -5
  17. package/dist/src/contract/ralph.js +2 -1
  18. package/dist/src/signer/tx-builder.d.ts +7 -1
  19. package/dist/src/signer/tx-builder.js +67 -0
  20. package/dist/src/signer/types.d.ts +27 -1
  21. package/dist/src/signer/types.js +3 -0
  22. package/dist/src/utils/sign.js +2 -2
  23. package/dist/src/utils/webcrypto.d.ts +3 -1
  24. package/package.json +1 -1
  25. package/src/address/address.ts +120 -12
  26. package/src/api/api-alephium.ts +134 -14
  27. package/src/api/node-provider.ts +3 -0
  28. package/src/api/types.ts +10 -5
  29. package/src/codec/lockup-script-codec.ts +19 -2
  30. package/src/codec/unlock-script-codec.ts +23 -8
  31. package/src/contract/contract.ts +33 -10
  32. package/src/contract/ralph.ts +5 -2
  33. package/src/signer/tx-builder.ts +88 -1
  34. package/src/signer/types.ts +34 -1
  35. package/src/utils/sign.ts +2 -2
@@ -23,6 +23,7 @@ const utils_1 = require("../utils");
23
23
  const codec_1 = require("../codec");
24
24
  const codec_2 = require("../codec/codec");
25
25
  const error_1 = require("../error");
26
+ const address_1 = require("../address");
26
27
  function encodeByteVec(hex) {
27
28
  if (!(0, utils_1.isHexString)(hex)) {
28
29
  throw Error(`Given value ${hex} is not a valid hex string`);
@@ -32,7 +33,7 @@ function encodeByteVec(hex) {
32
33
  }
33
34
  exports.encodeByteVec = encodeByteVec;
34
35
  function encodeAddress(address) {
35
- return utils_1.bs58.decode(address);
36
+ return (0, address_1.addressToBytes)(address);
36
37
  }
37
38
  exports.encodeAddress = encodeAddress;
38
39
  var VmValType;
@@ -1,5 +1,5 @@
1
1
  import { NodeProvider } from '../api';
2
- import { SignChainedTxParams, SignChainedTxResult, SignDeployContractTxParams, SignDeployContractTxResult, SignExecuteScriptTxParams, SignExecuteScriptTxResult, SignTransferTxParams, SignTransferTxResult, SignUnsignedTxParams, SignUnsignedTxResult } from './types';
2
+ import { SignChainedTxParams, SignChainedTxResult, SignDeployContractTxParams, SignDeployContractTxResult, SignExecuteScriptTxParams, SignExecuteScriptTxResult, SignTransferTxParams, SignTransferTxResult, SignUnsignedTxParams, SignUnsignedTxResult, SignGrouplessTransferTxParams, SignGrouplessDeployContractTxParams, SignGrouplessExecuteScriptTxParams } from './types';
3
3
  export declare abstract class TransactionBuilder {
4
4
  abstract get nodeProvider(): NodeProvider;
5
5
  static from(nodeProvider: NodeProvider): TransactionBuilder;
@@ -9,8 +9,14 @@ export declare abstract class TransactionBuilder {
9
9
  buildDeployContractTx(params: SignDeployContractTxParams, publicKey: string): Promise<Omit<SignDeployContractTxResult, 'signature'>>;
10
10
  buildExecuteScriptTx(params: SignExecuteScriptTxParams, publicKey: string): Promise<Omit<SignExecuteScriptTxResult, 'signature'>>;
11
11
  buildChainedTx(params: SignChainedTxParams[], publicKeys: string[]): Promise<Omit<SignChainedTxResult, 'signature'>[]>;
12
+ buildGrouplessTransferTx(params: SignGrouplessTransferTxParams): Promise<Omit<SignChainedTxResult, 'signature'>[]>;
13
+ buildGrouplessDeployContractTx(params: SignGrouplessDeployContractTxParams): Promise<Omit<SignChainedTxResult, 'signature'>[]>;
14
+ buildGrouplessExecuteScriptTx(params: SignGrouplessExecuteScriptTxParams): Promise<Omit<SignChainedTxResult, 'signature'>[]>;
12
15
  static buildUnsignedTx(params: SignUnsignedTxParams): Omit<SignUnsignedTxResult, 'signature'>;
13
16
  private buildTransferTxParams;
17
+ private buildGrouplessTransferTxParams;
18
+ private buildGrouplessDeployContractTxParams;
19
+ private buildGrouplessExecuteScriptTxParams;
14
20
  private buildDeployContractTxParams;
15
21
  private buildExecuteScriptTxParams;
16
22
  private convertTransferTxResult;
@@ -109,6 +109,42 @@ class TransactionBuilder {
109
109
  });
110
110
  return results;
111
111
  }
112
+ async buildGrouplessTransferTx(params) {
113
+ const data = this.buildGrouplessTransferTxParams(params);
114
+ const response = await this.nodeProvider.groupless.postGrouplessTransfer(data);
115
+ return response.map((result) => {
116
+ return {
117
+ ...this.convertTransferTxResult(result),
118
+ type: 'Transfer'
119
+ };
120
+ });
121
+ }
122
+ async buildGrouplessDeployContractTx(params) {
123
+ const data = this.buildGrouplessDeployContractTxParams(params);
124
+ const response = await this.nodeProvider.groupless.postGrouplessDeployContract(data);
125
+ const transferTxs = response.transferTxs.map((result) => ({
126
+ ...this.convertTransferTxResult(result),
127
+ type: 'Transfer'
128
+ }));
129
+ const deployContractTx = {
130
+ ...this.convertDeployContractTxResult(response.deployContractTx),
131
+ type: 'DeployContract'
132
+ };
133
+ return [...transferTxs, deployContractTx];
134
+ }
135
+ async buildGrouplessExecuteScriptTx(params) {
136
+ const data = this.buildGrouplessExecuteScriptTxParams(params);
137
+ const response = await this.nodeProvider.groupless.postGrouplessExecuteScript(data);
138
+ const transferTxs = response.transferTxs.map((result) => ({
139
+ ...this.convertTransferTxResult(result),
140
+ type: 'Transfer'
141
+ }));
142
+ const executeScriptTx = {
143
+ ...this.convertExecuteScriptTxResult(response.executeScriptTx),
144
+ type: 'ExecuteScript'
145
+ };
146
+ return [...transferTxs, executeScriptTx];
147
+ }
112
148
  static buildUnsignedTx(params) {
113
149
  const unsignedTxBin = (0, utils_1.hexToBinUnsafe)(params.unsignedTx);
114
150
  const decoded = codec_1.unsignedTxCodec.decode(unsignedTxBin);
@@ -134,6 +170,37 @@ class TransactionBuilder {
134
170
  ...rest
135
171
  };
136
172
  }
173
+ buildGrouplessTransferTxParams(params) {
174
+ return {
175
+ fromAddress: params.fromAddress,
176
+ destinations: (0, signer_1.toApiDestinations)(params.destinations),
177
+ gasPrice: (0, api_1.toApiNumber256Optional)(params.gasPrice),
178
+ targetBlockHash: params.targetBlockHash
179
+ };
180
+ }
181
+ buildGrouplessDeployContractTxParams(params) {
182
+ return {
183
+ fromAddress: params.fromAddress,
184
+ bytecode: params.bytecode,
185
+ initialAttoAlphAmount: (0, api_1.toApiNumber256Optional)(params.initialAttoAlphAmount),
186
+ initialTokenAmounts: (0, api_1.toApiTokens)(params.initialTokenAmounts),
187
+ issueTokenAmount: (0, api_1.toApiNumber256Optional)(params.issueTokenAmount),
188
+ issueTokenTo: params.issueTokenTo,
189
+ gasPrice: (0, api_1.toApiNumber256Optional)(params.gasPrice),
190
+ targetBlockHash: params.targetBlockHash
191
+ };
192
+ }
193
+ buildGrouplessExecuteScriptTxParams(params) {
194
+ return {
195
+ fromAddress: params.fromAddress,
196
+ bytecode: params.bytecode,
197
+ attoAlphAmount: (0, api_1.toApiNumber256Optional)(params.attoAlphAmount),
198
+ tokens: (0, api_1.toApiTokens)(params.tokens),
199
+ gasPrice: (0, api_1.toApiNumber256Optional)(params.gasPrice),
200
+ targetBlockHash: params.targetBlockHash,
201
+ gasEstimationMultiplier: params.gasEstimationMultiplier
202
+ };
203
+ }
137
204
  buildDeployContractTxParams(params, publicKey) {
138
205
  TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType);
139
206
  const { initialAttoAlphAmount, initialTokenAmounts, issueTokenAmount, gasPrice, ...rest } = params;
@@ -11,7 +11,7 @@ export interface Destination {
11
11
  lockTime?: number;
12
12
  message?: string;
13
13
  }
14
- export type KeyType = 'default' | 'bip340-schnorr';
14
+ export type KeyType = 'default' | 'bip340-schnorr' | 'groupless';
15
15
  export interface Account {
16
16
  keyType: KeyType;
17
17
  address: string;
@@ -113,6 +113,32 @@ export type SignExecuteScriptChainedTxResult = SignExecuteScriptTxResult & {
113
113
  type: 'ExecuteScript';
114
114
  };
115
115
  export type SignChainedTxResult = SignTransferChainedTxResult | SignDeployContractChainedTxResult | SignExecuteScriptChainedTxResult;
116
+ export interface SignGrouplessTransferTxParams {
117
+ fromAddress: string;
118
+ destinations: Destination[];
119
+ gasPrice?: Number256;
120
+ targetBlockHash?: string;
121
+ }
122
+ export interface SignGrouplessDeployContractTxParams {
123
+ fromAddress: string;
124
+ bytecode: string;
125
+ initialAttoAlphAmount?: Number256;
126
+ initialTokenAmounts?: Token[];
127
+ issueTokenAmount?: Number256;
128
+ issueTokenTo?: string;
129
+ gasPrice?: Number256;
130
+ targetBlockHash?: string;
131
+ }
132
+ export interface SignGrouplessExecuteScriptTxParams {
133
+ fromAddress: string;
134
+ bytecode: string;
135
+ attoAlphAmount?: Number256;
136
+ tokens?: Token[];
137
+ gasPrice?: Number256;
138
+ targetBlockHash?: string;
139
+ gasEstimationMultiplier?: number;
140
+ }
141
+ export type SignGrouplessTxParams = SignGrouplessTransferTxParams | SignGrouplessDeployContractTxParams | SignGrouplessExecuteScriptTxParams;
116
142
  export type MessageHasher = 'alephium' | 'sha256' | 'blake2b' | 'identity';
117
143
  export interface SignMessageParams {
118
144
  signerAddress: string;
@@ -28,3 +28,6 @@ utils_1.assertType;
28
28
  (0, utils_1.assertType)();
29
29
  utils_1.assertType;
30
30
  (0, utils_1.assertType)();
31
+ (0, utils_1.assertType)();
32
+ (0, utils_1.assertType)();
33
+ (0, utils_1.assertType)();
@@ -60,7 +60,7 @@ necc.utils.hmacSha256Sync = (key, ...messages) => {
60
60
  // hash has to be 32 bytes
61
61
  function sign(hash, privateKey, _keyType) {
62
62
  const keyType = _keyType ?? 'default';
63
- if (keyType === 'default') {
63
+ if (keyType === 'default' || keyType === 'groupless') {
64
64
  const key = ec.keyFromPrivate(privateKey);
65
65
  const signature = key.sign(hash);
66
66
  return (0, utils_1.encodeSignature)(signature);
@@ -74,7 +74,7 @@ exports.sign = sign;
74
74
  function verifySignature(hash, publicKey, signature, _keyType) {
75
75
  const keyType = _keyType ?? 'default';
76
76
  try {
77
- if (keyType === 'default') {
77
+ if (keyType === 'default' || keyType === 'groupless') {
78
78
  const key = ec.keyFromPublic(publicKey, 'hex');
79
79
  return key.verify(hash, (0, utils_1.signatureDecode)(ec, signature));
80
80
  }
@@ -1,4 +1,6 @@
1
+ /// <reference types="node" />
2
+ import { webcrypto } from 'crypto';
1
3
  export declare class WebCrypto {
2
- subtle: SubtleCrypto;
4
+ subtle: webcrypto.SubtleCrypto;
3
5
  getRandomValues<T extends ArrayBufferView | null>(array: T): T;
4
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alephium/web3",
3
- "version": "1.11.6",
3
+ "version": "1.12.0-beta.0",
4
4
  "description": "A JS/TS library to interact with the Alephium platform",
5
5
  "license": "GPL",
6
6
  "main": "dist/src/index.js",
@@ -24,10 +24,11 @@ import bs58, { base58ToBytes } from '../utils/bs58'
24
24
  import { binToHex, concatBytes, hexToBinUnsafe, isHexString, xorByte } from '../utils'
25
25
  import { KeyType } from '../signer'
26
26
  import { P2MPKH, lockupScriptCodec } from '../codec/lockup-script-codec'
27
- import { i32Codec } from '../codec'
27
+ import { i32Codec, intAs4BytesCodec } from '../codec'
28
28
  import { LockupScript } from '../codec/lockup-script-codec'
29
29
  import djb2 from '../utils/djb2'
30
30
  import { TraceableError } from '../error'
31
+ import { byteCodec } from '../codec/codec'
31
32
 
32
33
  const ec = new EC('secp256k1')
33
34
  const PublicKeyHashSize = 32
@@ -36,7 +37,8 @@ export enum AddressType {
36
37
  P2PKH = 0x00,
37
38
  P2MPKH = 0x01,
38
39
  P2SH = 0x02,
39
- P2C = 0x03
40
+ P2C = 0x03,
41
+ P2PK = 0x04
40
42
  }
41
43
 
42
44
  export function validateAddress(address: string) {
@@ -53,7 +55,7 @@ export function isValidAddress(address: string): boolean {
53
55
  }
54
56
 
55
57
  function decodeAndValidateAddress(address: string): Uint8Array {
56
- const decoded = base58ToBytes(address)
58
+ const decoded = addressToBytes(address)
57
59
  if (decoded.length === 0) throw new Error('Address is empty')
58
60
  const addressType = decoded[0]
59
61
  if (addressType === AddressType.P2MPKH) {
@@ -75,14 +77,77 @@ function decodeAndValidateAddress(address: string): Uint8Array {
75
77
  } else if (addressType === AddressType.P2PKH || addressType === AddressType.P2SH || addressType === AddressType.P2C) {
76
78
  // [type, ...hash]
77
79
  if (decoded.length === 33) return decoded
80
+ } else if (isGrouplessAddressWithGroup(decoded)) {
81
+ // [type, keyType, ...publicKey, ...checkSum, ...groupByte]
82
+ const publicKeyToIndex = decoded.length - 1 - 4
83
+ const publicKeyLikeBytes = decoded.slice(1, publicKeyToIndex)
84
+ const checksum = binToHex(decoded.slice(publicKeyToIndex, publicKeyToIndex + 4))
85
+ const expectedChecksum = binToHex(intAs4BytesCodec.encode(djb2(publicKeyLikeBytes)))
86
+ if (checksum !== expectedChecksum) {
87
+ throw new Error(`Invalid checksum for P2PK address: ${address}`)
88
+ }
89
+ const group = byteCodec.decode(decoded.slice(decoded.length - 1, decoded.length))
90
+ validateGroupIndex(group)
91
+
92
+ return decoded
78
93
  }
79
94
 
80
95
  throw new Error(`Invalid address: ${address}`)
81
96
  }
82
97
 
98
+ function isGrouplessAddressWithoutGroup(decoded: Uint8Array): boolean {
99
+ return decoded[0] === AddressType.P2PK && (decoded.length === 38 || decoded.length === 39)
100
+ }
101
+
102
+ function isGrouplessAddressWithGroup(decoded: Uint8Array): boolean {
103
+ return decoded[0] === AddressType.P2PK && (decoded.length === 39 || decoded.length === 40)
104
+ }
105
+
106
+ export function addressToBytes(address: string): Uint8Array {
107
+ if (hasExplicitGroupIndex(address)) {
108
+ const groupIndex = parseGroupIndex(address[address.length - 1])
109
+ const decoded = base58ToBytes(address.slice(0, address.length - 2))
110
+ if (isGrouplessAddressWithoutGroup(decoded)) {
111
+ const groupByte = byteCodec.encode(groupIndex)
112
+ return new Uint8Array([...decoded, ...groupByte])
113
+ }
114
+ throw new Error(`Invalid groupless address: ${address}`)
115
+ } else {
116
+ const decoded = base58ToBytes(address)
117
+ if (isGrouplessAddressWithoutGroup(decoded)) {
118
+ const group = defaultGroupOfGrouplessAddress(decoded.slice(2, decoded.length - 4))
119
+ const groupByte = byteCodec.encode(group)
120
+ return new Uint8Array([...decoded, ...groupByte])
121
+ }
122
+ return decoded
123
+ }
124
+ }
125
+
83
126
  export function isAssetAddress(address: string) {
84
127
  const addressType = decodeAndValidateAddress(address)[0]
85
- return addressType === AddressType.P2PKH || addressType === AddressType.P2MPKH || addressType === AddressType.P2SH
128
+ return (
129
+ addressType === AddressType.P2PKH ||
130
+ addressType === AddressType.P2MPKH ||
131
+ addressType === AddressType.P2SH ||
132
+ addressType === AddressType.P2PK
133
+ )
134
+ }
135
+
136
+ export function isGrouplessAddress(address: string) {
137
+ const addressType = decodeAndValidateAddress(address)[0]
138
+ return addressType === AddressType.P2PK
139
+ }
140
+
141
+ export function isGrouplessAddressWithoutGroupIndex(address: string) {
142
+ return !hasExplicitGroupIndex(address) && isGrouplessAddress(address)
143
+ }
144
+
145
+ export function isGrouplessAddressWithGroupIndex(address: string) {
146
+ return hasExplicitGroupIndex(address) && isGrouplessAddress(address)
147
+ }
148
+
149
+ export function defaultGroupOfGrouplessAddress(pubKey: Uint8Array): number {
150
+ return pubKey[pubKey.length - 1] & 0xff % TOTAL_NUMBER_OF_GROUPS
86
151
  }
87
152
 
88
153
  export function isContractAddress(address: string) {
@@ -101,6 +166,8 @@ export function groupOfAddress(address: string): number {
101
166
  return groupOfP2mpkhAddress(addressBody)
102
167
  } else if (addressType == AddressType.P2SH) {
103
168
  return groupOfP2shAddress(addressBody)
169
+ } else if (addressType == AddressType.P2PK) {
170
+ return groupOfP2pkAddress(addressBody)
104
171
  } else {
105
172
  // Contract Address
106
173
  const id = contractIdFromAddress(address)
@@ -110,17 +177,21 @@ export function groupOfAddress(address: string): number {
110
177
 
111
178
  // Pay to public key hash address
112
179
  function groupOfP2pkhAddress(address: Uint8Array): number {
113
- return groupFromBytesForAssetAddress(address)
180
+ return groupFromBytes(address)
114
181
  }
115
182
 
116
183
  // Pay to multiple public key hash address
117
184
  function groupOfP2mpkhAddress(address: Uint8Array): number {
118
- return groupFromBytesForAssetAddress(address.slice(1, 33))
185
+ return groupFromBytes(address.slice(1, 33))
186
+ }
187
+
188
+ function groupOfP2pkAddress(address: Uint8Array): number {
189
+ return byteCodec.decode(address.slice(38, 39)) % TOTAL_NUMBER_OF_GROUPS
119
190
  }
120
191
 
121
192
  // Pay to script hash address
122
193
  function groupOfP2shAddress(address: Uint8Array): number {
123
- return groupFromBytesForAssetAddress(address)
194
+ return groupFromBytes(address)
124
195
  }
125
196
 
126
197
  export function contractIdFromAddress(address: string): Uint8Array {
@@ -151,7 +222,7 @@ export function groupOfPrivateKey(privateKey: string, keyType?: KeyType): number
151
222
  export function publicKeyFromPrivateKey(privateKey: string, _keyType?: KeyType): string {
152
223
  const keyType = _keyType ?? 'default'
153
224
 
154
- if (keyType === 'default') {
225
+ if (keyType === 'default' || keyType === 'groupless') {
155
226
  const key = ec.keyFromPrivate(privateKey)
156
227
  return key.getPublic(true, 'hex')
157
228
  } else {
@@ -166,6 +237,11 @@ export function addressFromPublicKey(publicKey: string, _keyType?: KeyType): str
166
237
  const hash = blake.blake2b(hexToBinUnsafe(publicKey), undefined, 32)
167
238
  const bytes = new Uint8Array([AddressType.P2PKH, ...hash])
168
239
  return bs58.encode(bytes)
240
+ } else if (keyType === 'groupless') {
241
+ const publicKeyBytes = new Uint8Array([0x00, ...hexToBinUnsafe(publicKey)])
242
+ const hashBytes = intAs4BytesCodec.encode(djb2(publicKeyBytes))
243
+ const bytes = new Uint8Array([0x04, ...publicKeyBytes, ...hashBytes])
244
+ return bs58.encode(bytes)
169
245
  } else {
170
246
  const lockupScript = hexToBinUnsafe(`0101000000000458144020${publicKey}8685`)
171
247
  return addressFromScript(lockupScript)
@@ -215,11 +291,13 @@ export function subContractId(parentContractId: string, pathInHex: string, group
215
291
 
216
292
  export function groupOfLockupScript(lockupScript: LockupScript): number {
217
293
  if (lockupScript.kind === 'P2PKH') {
218
- return groupFromBytesForAssetAddress(lockupScript.value)
294
+ return groupFromBytes(lockupScript.value)
219
295
  } else if (lockupScript.kind === 'P2MPKH') {
220
- return groupFromBytesForAssetAddress(lockupScript.value.publicKeyHashes[0])
296
+ return groupFromBytes(lockupScript.value.publicKeyHashes[0])
221
297
  } else if (lockupScript.kind === 'P2SH') {
222
- return groupFromBytesForAssetAddress(lockupScript.value)
298
+ return groupFromBytes(lockupScript.value)
299
+ } else if (lockupScript.kind === 'P2PK') {
300
+ return lockupScript.value.group % TOTAL_NUMBER_OF_GROUPS
223
301
  } else {
224
302
  // P2C
225
303
  const contractId = lockupScript.value
@@ -227,8 +305,38 @@ export function groupOfLockupScript(lockupScript: LockupScript): number {
227
305
  }
228
306
  }
229
307
 
230
- function groupFromBytesForAssetAddress(bytes: Uint8Array): number {
308
+ export function groupFromBytes(bytes: Uint8Array): number {
231
309
  const hint = djb2(bytes) | 1
310
+ return groupFromHint(hint)
311
+ }
312
+
313
+ export function groupFromHint(hint: number): number {
232
314
  const hash = xorByte(hint)
233
315
  return hash % TOTAL_NUMBER_OF_GROUPS
234
316
  }
317
+
318
+ export function hasExplicitGroupIndex(address: string): boolean {
319
+ return address.length > 2 && address[address.length - 2] === ':'
320
+ }
321
+
322
+ export function addressFromLockupScript(lockupScript: LockupScript): string {
323
+ if (lockupScript.kind === 'P2PK') {
324
+ const groupByte = lockupScriptCodec.encode(lockupScript).slice(-1)
325
+ const address = bs58.encode(lockupScriptCodec.encode(lockupScript).slice(0, -1))
326
+ return `${address}:${groupByte}`
327
+ } else {
328
+ return bs58.encode(lockupScriptCodec.encode(lockupScript))
329
+ }
330
+ }
331
+
332
+ function parseGroupIndex(groupIndexStr: string): number {
333
+ return validateGroupIndex(parseInt(groupIndexStr), groupIndexStr)
334
+ }
335
+
336
+ function validateGroupIndex(groupIndex: number, groupIndexStr?: string): number {
337
+ if (isNaN(groupIndex) || groupIndex < 0 || groupIndex >= TOTAL_NUMBER_OF_GROUPS) {
338
+ throw new Error(`Invalid group index: ${groupIndexStr ?? groupIndex}`)
339
+ }
340
+
341
+ return groupIndex
342
+ }
@@ -320,6 +320,62 @@ export interface BuildExecuteScriptTxResult {
320
320
  simulationResult: SimulationResult
321
321
  }
322
322
 
323
+ /** BuildGrouplessDeployContractTx */
324
+ export interface BuildGrouplessDeployContractTx {
325
+ fromAddress: string
326
+ /** @format hex-string */
327
+ bytecode: string
328
+ /** @format uint256 */
329
+ initialAttoAlphAmount?: string
330
+ initialTokenAmounts?: Token[]
331
+ /** @format uint256 */
332
+ issueTokenAmount?: string
333
+ /** @format address */
334
+ issueTokenTo?: string
335
+ /** @format uint256 */
336
+ gasPrice?: string
337
+ /** @format block-hash */
338
+ targetBlockHash?: string
339
+ }
340
+
341
+ /** BuildGrouplessDeployContractTxResult */
342
+ export interface BuildGrouplessDeployContractTxResult {
343
+ transferTxs: BuildTransferTxResult[]
344
+ deployContractTx: BuildDeployContractTxResult
345
+ }
346
+
347
+ /** BuildGrouplessExecuteScriptTx */
348
+ export interface BuildGrouplessExecuteScriptTx {
349
+ fromAddress: string
350
+ /** @format hex-string */
351
+ bytecode: string
352
+ /** @format uint256 */
353
+ attoAlphAmount?: string
354
+ tokens?: Token[]
355
+ /** @format uint256 */
356
+ gasPrice?: string
357
+ /** @format block-hash */
358
+ targetBlockHash?: string
359
+ /** @format double */
360
+ gasEstimationMultiplier?: number
361
+ }
362
+
363
+ /** BuildGrouplessExecuteScriptTxResult */
364
+ export interface BuildGrouplessExecuteScriptTxResult {
365
+ transferTxs: BuildTransferTxResult[]
366
+ executeScriptTx: BuildExecuteScriptTxResult
367
+ }
368
+
369
+ /** BuildGrouplessTransferTx */
370
+ export interface BuildGrouplessTransferTx {
371
+ fromAddress: string
372
+ destinations: Destination[]
373
+ /** @format uint256 */
374
+ gasPrice?: string
375
+ /** @format block-hash */
376
+ targetBlockHash?: string
377
+ }
378
+
323
379
  /** BuildInfo */
324
380
  export interface BuildInfo {
325
381
  releaseVersion: string
@@ -1564,8 +1620,8 @@ export class HttpClient<SecurityDataType = unknown> {
1564
1620
  property instanceof Blob
1565
1621
  ? property
1566
1622
  : typeof property === 'object' && property !== null
1567
- ? JSON.stringify(property)
1568
- : `${property}`
1623
+ ? JSON.stringify(property)
1624
+ : `${property}`
1569
1625
  )
1570
1626
  return formData
1571
1627
  }, new FormData()),
@@ -1645,18 +1701,18 @@ export class HttpClient<SecurityDataType = unknown> {
1645
1701
  const data = !responseFormat
1646
1702
  ? r
1647
1703
  : await response[responseFormat]()
1648
- .then((data) => {
1649
- if (r.ok) {
1650
- r.data = data
1651
- } else {
1652
- r.error = data
1653
- }
1654
- return r
1655
- })
1656
- .catch((e) => {
1657
- r.error = e
1658
- return r
1659
- })
1704
+ .then((data) => {
1705
+ if (r.ok) {
1706
+ r.data = data
1707
+ } else {
1708
+ r.error = data
1709
+ }
1710
+ return r
1711
+ })
1712
+ .catch((e) => {
1713
+ r.error = e
1714
+ return r
1715
+ })
1660
1716
 
1661
1717
  if (cancelToken) {
1662
1718
  this.abortControllers.delete(cancelToken)
@@ -3722,4 +3778,68 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
3722
3778
  ...params
3723
3779
  }).then(convertHttpResponse)
3724
3780
  }
3781
+ groupless = {
3782
+ /**
3783
+ * No description
3784
+ *
3785
+ * @tags Groupless
3786
+ * @name PostGrouplessTransfer
3787
+ * @summary Build unsigned transfer transactions from a groupless address
3788
+ * @request POST:/groupless/transfer
3789
+ */
3790
+ postGrouplessTransfer: (data: BuildGrouplessTransferTx, params: RequestParams = {}) =>
3791
+ this.request<
3792
+ BuildTransferTxResult[],
3793
+ BadRequest | Unauthorized | NotFound | InternalServerError | ServiceUnavailable | GatewayTimeout
3794
+ >({
3795
+ path: `/groupless/transfer`,
3796
+ method: 'POST',
3797
+ body: data,
3798
+ type: ContentType.Json,
3799
+ format: 'json',
3800
+ ...params
3801
+ }).then(convertHttpResponse),
3802
+
3803
+ /**
3804
+ * No description
3805
+ *
3806
+ * @tags Groupless
3807
+ * @name PostGrouplessExecuteScript
3808
+ * @summary Build an unsigned execute script transaction from a groupless address
3809
+ * @request POST:/groupless/execute-script
3810
+ */
3811
+ postGrouplessExecuteScript: (data: BuildGrouplessExecuteScriptTx, params: RequestParams = {}) =>
3812
+ this.request<
3813
+ BuildGrouplessExecuteScriptTxResult,
3814
+ BadRequest | Unauthorized | NotFound | InternalServerError | ServiceUnavailable | GatewayTimeout
3815
+ >({
3816
+ path: `/groupless/execute-script`,
3817
+ method: 'POST',
3818
+ body: data,
3819
+ type: ContentType.Json,
3820
+ format: 'json',
3821
+ ...params
3822
+ }).then(convertHttpResponse),
3823
+
3824
+ /**
3825
+ * No description
3826
+ *
3827
+ * @tags Groupless
3828
+ * @name PostGrouplessDeployContract
3829
+ * @summary Build an unsigned deploy contract transaction from a groupless address
3830
+ * @request POST:/groupless/deploy-contract
3831
+ */
3832
+ postGrouplessDeployContract: (data: BuildGrouplessDeployContractTx, params: RequestParams = {}) =>
3833
+ this.request<
3834
+ BuildGrouplessDeployContractTxResult,
3835
+ BadRequest | Unauthorized | NotFound | InternalServerError | ServiceUnavailable | GatewayTimeout
3836
+ >({
3837
+ path: `/groupless/deploy-contract`,
3838
+ method: 'POST',
3839
+ body: data,
3840
+ type: ContentType.Json,
3841
+ format: 'json',
3842
+ ...params
3843
+ }).then(convertHttpResponse)
3844
+ }
3725
3845
  }
@@ -55,6 +55,7 @@ interface NodeProviderApis {
55
55
  utils: NodeApi<string>['utils']
56
56
  miners: NodeApi<string>['miners']
57
57
  events: NodeApi<string>['events']
58
+ groupless: NodeApi<string>['groupless']
58
59
  }
59
60
 
60
61
  export class NodeProvider implements NodeProviderApis {
@@ -69,6 +70,7 @@ export class NodeProvider implements NodeProviderApis {
69
70
  readonly utils: NodeApi<string>['utils']
70
71
  readonly miners: NodeApi<string>['miners']
71
72
  readonly events: NodeApi<string>['events']
73
+ readonly groupless: NodeApi<string>['groupless']
72
74
 
73
75
  constructor(baseUrl: string, apiKey?: string, customFetch?: typeof fetch)
74
76
  constructor(provider: NodeProvider)
@@ -95,6 +97,7 @@ export class NodeProvider implements NodeProviderApis {
95
97
  this.utils = { ...nodeApi.utils }
96
98
  this.miners = { ...nodeApi.miners }
97
99
  this.events = { ...nodeApi.events }
100
+ this.groupless = { ...nodeApi.groupless }
98
101
  requestWithLog(this)
99
102
  }
100
103
 
package/src/api/types.ts CHANGED
@@ -16,6 +16,7 @@ You should have received a copy of the GNU Lesser General Public License
16
16
  along with the library. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
 
19
+ import { hasExplicitGroupIndex } from '../address'
19
20
  import { ZERO_ADDRESS } from '../constants'
20
21
  import { isDebugModeEnabled } from '../debug'
21
22
  import { TraceableError } from '../error'
@@ -99,14 +100,18 @@ export function toApiByteVec(v: Val): string {
99
100
  throw new Error(`Invalid hex-string: ${v}`)
100
101
  }
101
102
 
102
- export function toApiAddress(v: Val): string {
103
- if (typeof v === 'string') {
103
+ export function toApiAddress(v0: Val): string {
104
+ if (typeof v0 === 'string') {
105
+ let v = v0
106
+ if (hasExplicitGroupIndex(v)) {
107
+ v = v.slice(0, -2)
108
+ }
104
109
  if (isBase58(v)) {
105
- return v
110
+ return v0
106
111
  }
107
- throw new Error(`Invalid base58 string: ${v}`)
112
+ throw new Error(`Invalid base58 string: ${v0}`)
108
113
  } else {
109
- throw new Error(`Invalid value: ${v}, expected a base58 string`)
114
+ throw new Error(`Invalid value: ${v0}, expected a base58 string`)
110
115
  }
111
116
  }
112
117