@alephium/web3 0.5.0-rc.1 → 0.5.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.
- package/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.LICENSE.txt +2 -0
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/src/api/api-alephium.d.ts +57 -20
- package/dist/src/api/api-alephium.js +57 -15
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/api/types.d.ts +1 -1
- package/dist/src/api/types.js +6 -2
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.js +2 -1
- package/dist/src/contract/contract.d.ts +9 -4
- package/dist/src/contract/contract.js +31 -14
- package/dist/src/signer/signer.d.ts +23 -30
- package/dist/src/signer/signer.js +34 -25
- package/dist/src/signer/tx-builder.d.ts +2 -7
- package/dist/src/signer/tx-builder.js +10 -7
- package/dist/src/signer/types.d.ts +8 -15
- package/dist/src/transaction/sign-verify.d.ts +3 -2
- package/dist/src/transaction/sign-verify.js +4 -14
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +1 -0
- package/dist/src/utils/sign.d.ts +3 -0
- package/dist/src/utils/sign.js +89 -0
- package/dist/src/utils/utils.d.ts +4 -3
- package/dist/src/utils/utils.js +25 -10
- package/package.json +2 -1
- package/src/api/api-alephium.ts +88 -32
- package/src/api/index.ts +2 -0
- package/src/api/types.ts +12 -2
- package/src/constants.ts +1 -0
- package/src/contract/contract.ts +49 -20
- package/src/signer/signer.ts +58 -61
- package/src/signer/tx-builder.ts +13 -7
- package/src/signer/types.ts +10 -9
- package/src/transaction/sign-verify.ts +10 -15
- package/src/utils/index.ts +1 -0
- package/src/utils/sign.ts +66 -0
- package/src/utils/utils.ts +26 -10
package/src/contract/contract.ts
CHANGED
|
@@ -848,38 +848,45 @@ export class Contract extends Artifact {
|
|
|
848
848
|
}
|
|
849
849
|
|
|
850
850
|
static ContractCreatedEventIndex = -1
|
|
851
|
-
static ContractCreatedEvent:
|
|
851
|
+
static ContractCreatedEvent: SystemEventSig = {
|
|
852
852
|
name: 'ContractCreated',
|
|
853
853
|
fieldNames: ['address'],
|
|
854
|
-
fieldTypes: ['Address']
|
|
854
|
+
fieldTypes: ['Address'],
|
|
855
|
+
optionalFieldNames: ['parentAddress'],
|
|
856
|
+
optionalFieldTypes: ['Address']
|
|
855
857
|
}
|
|
856
858
|
|
|
857
859
|
static ContractDestroyedEventIndex = -2
|
|
858
|
-
static ContractDestroyedEvent:
|
|
860
|
+
static ContractDestroyedEvent: SystemEventSig = {
|
|
859
861
|
name: 'ContractDestroyed',
|
|
860
862
|
fieldNames: ['address'],
|
|
861
863
|
fieldTypes: ['Address']
|
|
862
864
|
}
|
|
863
865
|
|
|
864
866
|
static fromApiEvent(event: node.ContractEventByTxId, codeHash: string | undefined, txId: string): ContractEvent {
|
|
865
|
-
let
|
|
867
|
+
let fields: Fields
|
|
868
|
+
let name: string
|
|
866
869
|
|
|
867
870
|
if (event.eventIndex == Contract.ContractCreatedEventIndex) {
|
|
868
|
-
|
|
871
|
+
fields = fromApiSystemEventFields(event.fields, Contract.ContractCreatedEvent)
|
|
872
|
+
name = Contract.ContractCreatedEvent.name
|
|
869
873
|
} else if (event.eventIndex == Contract.ContractDestroyedEventIndex) {
|
|
870
|
-
|
|
874
|
+
fields = fromApiSystemEventFields(event.fields, Contract.ContractDestroyedEvent)
|
|
875
|
+
name = Contract.ContractDestroyedEvent.name
|
|
871
876
|
} else {
|
|
872
877
|
const contract = Project.currentProject.contractByCodeHash(codeHash!)
|
|
873
|
-
eventSig = contract.eventsSig[event.eventIndex]
|
|
878
|
+
const eventSig = contract.eventsSig[event.eventIndex]
|
|
879
|
+
fields = fromApiEventFields(event.fields, eventSig)
|
|
880
|
+
name = eventSig.name
|
|
874
881
|
}
|
|
875
882
|
|
|
876
883
|
return {
|
|
877
884
|
txId: txId,
|
|
878
885
|
blockHash: event.blockHash,
|
|
879
886
|
contractAddress: event.contractAddress,
|
|
880
|
-
name:
|
|
887
|
+
name: name,
|
|
881
888
|
eventIndex: event.eventIndex,
|
|
882
|
-
fields:
|
|
889
|
+
fields: fields
|
|
883
890
|
}
|
|
884
891
|
}
|
|
885
892
|
|
|
@@ -913,8 +920,10 @@ export class Contract extends Artifact {
|
|
|
913
920
|
params: DeployContractParams<P>
|
|
914
921
|
): Promise<SignDeployContractTxParams> {
|
|
915
922
|
const bytecode = this.buildByteCodeToDeploy(params.initialFields ?? {})
|
|
923
|
+
const selectedAccount = await signer.getSelectedAccount()
|
|
916
924
|
const signerParams: SignDeployContractTxParams = {
|
|
917
|
-
signerAddress:
|
|
925
|
+
signerAddress: selectedAccount.address,
|
|
926
|
+
signerKeyType: selectedAccount.keyType,
|
|
918
927
|
bytecode: bytecode,
|
|
919
928
|
initialAttoAlphAmount: params?.initialAttoAlphAmount,
|
|
920
929
|
issueTokenAmount: params?.issueTokenAmount,
|
|
@@ -1056,8 +1065,10 @@ export class Script extends Artifact {
|
|
|
1056
1065
|
signer: SignerProvider,
|
|
1057
1066
|
params: ExecuteScriptParams<P>
|
|
1058
1067
|
): Promise<SignExecuteScriptTxParams> {
|
|
1068
|
+
const selectedAccount = await signer.getSelectedAccount()
|
|
1059
1069
|
const signerParams: SignExecuteScriptTxParams = {
|
|
1060
|
-
signerAddress:
|
|
1070
|
+
signerAddress: selectedAccount.address,
|
|
1071
|
+
signerKeyType: selectedAccount.keyType,
|
|
1061
1072
|
bytecode: this.buildByteCodeToDeploy(params.initialFields ?? {}),
|
|
1062
1073
|
attoAlphAmount: params.attoAlphAmount,
|
|
1063
1074
|
tokens: params.tokens,
|
|
@@ -1095,6 +1106,16 @@ function fromApiEventFields(vals: node.Val[], eventSig: node.EventSig): Fields {
|
|
|
1095
1106
|
return fromApiVals(vals, eventSig.fieldNames, eventSig.fieldTypes)
|
|
1096
1107
|
}
|
|
1097
1108
|
|
|
1109
|
+
function fromApiSystemEventFields(vals: node.Val[], systemEventSig: SystemEventSig): Fields {
|
|
1110
|
+
return fromApiVals(
|
|
1111
|
+
vals,
|
|
1112
|
+
systemEventSig.fieldNames,
|
|
1113
|
+
systemEventSig.fieldTypes,
|
|
1114
|
+
systemEventSig.optionalFieldNames ?? [],
|
|
1115
|
+
systemEventSig.optionalFieldTypes ?? []
|
|
1116
|
+
)
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1098
1119
|
export interface Asset {
|
|
1099
1120
|
alphAmount: Number256
|
|
1100
1121
|
tokens?: Token[]
|
|
@@ -1272,7 +1293,7 @@ export interface DeployContractParams<P extends Fields = Fields> {
|
|
|
1272
1293
|
assertType<
|
|
1273
1294
|
Eq<
|
|
1274
1295
|
Omit<DeployContractParams<undefined>, 'initialFields'>,
|
|
1275
|
-
Omit<SignDeployContractTxParams, 'signerAddress' | 'bytecode'>
|
|
1296
|
+
Omit<SignDeployContractTxParams, 'signerAddress' | 'signerKeyType' | 'bytecode'>
|
|
1276
1297
|
>
|
|
1277
1298
|
>
|
|
1278
1299
|
export type DeployContractResult<T> = SignDeployContractTxResult & { instance: T }
|
|
@@ -1339,37 +1360,45 @@ export interface CallContractResult<R> {
|
|
|
1339
1360
|
events: ContractEvent[]
|
|
1340
1361
|
}
|
|
1341
1362
|
|
|
1342
|
-
export
|
|
1343
|
-
|
|
1363
|
+
export interface SystemEventSig extends EventSig {
|
|
1364
|
+
optionalFieldNames?: string[]
|
|
1365
|
+
optionalFieldTypes?: string[]
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
export type ContractCreatedEvent = ContractEvent<{ address: Address; parentAddress?: Address }>
|
|
1369
|
+
export type ContractDestroyedEvent = ContractEvent<{ address: Address }>
|
|
1344
1370
|
|
|
1345
|
-
function
|
|
1371
|
+
function decodeSystemEvent(event: node.ContractEvent, systemEventSig: SystemEventSig, eventIndex: number): Fields {
|
|
1346
1372
|
if (event.eventIndex !== eventIndex) {
|
|
1347
1373
|
throw new Error(`Invalid event index: ${event.eventIndex}, expected: ${eventIndex}`)
|
|
1348
1374
|
}
|
|
1349
|
-
return
|
|
1375
|
+
return fromApiSystemEventFields(event.fields, systemEventSig)
|
|
1350
1376
|
}
|
|
1351
1377
|
|
|
1352
1378
|
export function decodeContractCreatedEvent(event: node.ContractEvent): Omit<ContractCreatedEvent, 'contractAddress'> {
|
|
1353
|
-
const fields =
|
|
1379
|
+
const fields = decodeSystemEvent(event, Contract.ContractCreatedEvent, Contract.ContractCreatedEventIndex)
|
|
1354
1380
|
return {
|
|
1355
1381
|
blockHash: event.blockHash,
|
|
1356
1382
|
txId: event.txId,
|
|
1357
1383
|
eventIndex: event.eventIndex,
|
|
1358
1384
|
name: Contract.ContractCreatedEvent.name,
|
|
1359
|
-
fields: {
|
|
1385
|
+
fields: {
|
|
1386
|
+
address: fields['address'] as Address,
|
|
1387
|
+
parentAddress: fields['parentAddress'] === undefined ? undefined : (fields['parentAddress'] as Address)
|
|
1388
|
+
}
|
|
1360
1389
|
}
|
|
1361
1390
|
}
|
|
1362
1391
|
|
|
1363
1392
|
export function decodeContractDestroyedEvent(
|
|
1364
1393
|
event: node.ContractEvent
|
|
1365
1394
|
): Omit<ContractDestroyedEvent, 'contractAddress'> {
|
|
1366
|
-
const fields =
|
|
1395
|
+
const fields = decodeSystemEvent(event, Contract.ContractDestroyedEvent, Contract.ContractDestroyedEventIndex)
|
|
1367
1396
|
return {
|
|
1368
1397
|
blockHash: event.blockHash,
|
|
1369
1398
|
txId: event.txId,
|
|
1370
1399
|
eventIndex: event.eventIndex,
|
|
1371
1400
|
name: Contract.ContractDestroyedEvent.name,
|
|
1372
|
-
fields: { address: fields['address'] as
|
|
1401
|
+
fields: { address: fields['address'] as Address }
|
|
1373
1402
|
}
|
|
1374
1403
|
}
|
|
1375
1404
|
|
package/src/signer/signer.ts
CHANGED
|
@@ -16,7 +16,6 @@ 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 { ec as EC } from 'elliptic'
|
|
20
19
|
import { ExplorerProvider, fromApiNumber256, fromApiTokens, NodeProvider, toApiNumber256, toApiTokens } from '../api'
|
|
21
20
|
import { node } from '../api'
|
|
22
21
|
import * as utils from '../utils'
|
|
@@ -39,57 +38,57 @@ import {
|
|
|
39
38
|
SignUnsignedTxResult,
|
|
40
39
|
SubmissionResult,
|
|
41
40
|
SubmitTransactionParams,
|
|
42
|
-
|
|
43
|
-
ExtSignDeployContractTxParams,
|
|
44
|
-
ExtSignExecuteScriptTxParams,
|
|
45
|
-
ExtSignUnsignedTxParams,
|
|
46
|
-
ExtSignMessageParams
|
|
41
|
+
KeyType
|
|
47
42
|
} from './types'
|
|
48
43
|
import { TransactionBuilder } from './tx-builder'
|
|
44
|
+
import { addressFromPublicKey, groupOfAddress } from '../utils'
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
export abstract class SignerProvider {
|
|
47
|
+
abstract get nodeProvider(): NodeProvider | undefined
|
|
48
|
+
abstract get explorerProvider(): ExplorerProvider | undefined
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
protected abstract unsafeGetSelectedAccount(): Promise<Account>
|
|
51
|
+
async getSelectedAccount(): Promise<Account> {
|
|
52
|
+
const account = await this.unsafeGetSelectedAccount()
|
|
53
|
+
SignerProvider.validateAccount(account)
|
|
54
|
+
return account
|
|
55
|
+
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
static validateAccount(account: Account): void {
|
|
58
|
+
const derivedAddress = addressFromPublicKey(account.publicKey, account.keyType)
|
|
59
|
+
const derivedGroup = groupOfAddress(derivedAddress)
|
|
60
|
+
if (derivedAddress !== account.address || derivedGroup !== account.group) {
|
|
61
|
+
throw Error(`Invalid accounot data: ${JSON.stringify(account)}`)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
57
64
|
|
|
58
|
-
signAndSubmitTransferTx(params: SignTransferTxParams): Promise<SignTransferTxResult>
|
|
59
|
-
signAndSubmitDeployContractTx(params: SignDeployContractTxParams): Promise<SignDeployContractTxResult>
|
|
60
|
-
signAndSubmitExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<SignExecuteScriptTxResult>
|
|
61
|
-
signAndSubmitUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
65
|
+
abstract signAndSubmitTransferTx(params: SignTransferTxParams): Promise<SignTransferTxResult>
|
|
66
|
+
abstract signAndSubmitDeployContractTx(params: SignDeployContractTxParams): Promise<SignDeployContractTxResult>
|
|
67
|
+
abstract signAndSubmitExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<SignExecuteScriptTxResult>
|
|
68
|
+
abstract signAndSubmitUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
62
69
|
|
|
63
|
-
signUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
70
|
+
abstract signUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
64
71
|
// The message will be prefixed with 'Alephium Signed Message: ' before signing
|
|
65
72
|
// so that the resulted signature cannot be reused for building transactions.
|
|
66
|
-
signMessage(params: SignMessageParams): Promise<SignMessageResult>
|
|
73
|
+
abstract signMessage(params: SignMessageParams): Promise<SignMessageResult>
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
// Abstraction for interactive signer (e.g. WalletConnect instance, Extension wallet object)
|
|
70
|
-
export
|
|
71
|
-
extends
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
signAndSubmitUnsignedTx(params: ExtSignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
80
|
-
signUnsignedTx(params: ExtSignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
81
|
-
signMessage(params: ExtSignMessageParams): Promise<SignMessageResult>
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export abstract class SignerProviderSimple extends TransactionBuilder implements SignerProvider {
|
|
85
|
-
abstract get explorerProvider(): ExplorerProvider | undefined
|
|
77
|
+
export abstract class InteractiveSignerProvider<
|
|
78
|
+
EnableOptions extends EnableOptionsBase = EnableOptionsBase
|
|
79
|
+
> extends SignerProvider {
|
|
80
|
+
protected abstract unsafeEnable(opt?: EnableOptions): Promise<Account>
|
|
81
|
+
async enable(opt?: EnableOptions): Promise<Account> {
|
|
82
|
+
const account = await this.unsafeEnable(opt)
|
|
83
|
+
SignerProvider.validateAccount(account)
|
|
84
|
+
return account
|
|
85
|
+
}
|
|
86
86
|
|
|
87
|
-
abstract
|
|
87
|
+
abstract disconnect(): Promise<void>
|
|
88
|
+
}
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return account.address
|
|
92
|
-
}
|
|
90
|
+
export abstract class SignerProviderSimple extends SignerProvider {
|
|
91
|
+
abstract override get nodeProvider(): NodeProvider
|
|
93
92
|
|
|
94
93
|
async submitTransaction(params: SubmitTransactionParams): Promise<SubmissionResult> {
|
|
95
94
|
const data: node.SubmitTransaction = { unsignedTx: params.unsignedTx, signature: params.signature }
|
|
@@ -133,8 +132,11 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
133
132
|
return { signature, ...response }
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
return
|
|
135
|
+
async buildTransferTx(params: SignTransferTxParams): Promise<Omit<SignTransferTxResult, 'signature'>> {
|
|
136
|
+
return TransactionBuilder.from(this.nodeProvider).buildTransferTx(
|
|
137
|
+
params,
|
|
138
|
+
await this.getPublicKey(params.signerAddress)
|
|
139
|
+
)
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
async signDeployContractTx(params: SignDeployContractTxParams): Promise<SignDeployContractTxResult> {
|
|
@@ -143,10 +145,13 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
143
145
|
return { signature, ...response }
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
|
|
148
|
+
async buildDeployContractTx(
|
|
147
149
|
params: SignDeployContractTxParams
|
|
148
150
|
): Promise<Omit<SignDeployContractTxResult, 'signature'>> {
|
|
149
|
-
return
|
|
151
|
+
return TransactionBuilder.from(this.nodeProvider).buildDeployContractTx(
|
|
152
|
+
params,
|
|
153
|
+
await this.getPublicKey(params.signerAddress)
|
|
154
|
+
)
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
async signExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<SignExecuteScriptTxResult> {
|
|
@@ -155,16 +160,17 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
155
160
|
return { signature, ...response }
|
|
156
161
|
}
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
async buildExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<Omit<SignExecuteScriptTxResult, 'signature'>> {
|
|
164
|
+
return TransactionBuilder.from(this.nodeProvider).buildExecuteScriptTx(
|
|
165
|
+
params,
|
|
166
|
+
await this.getPublicKey(params.signerAddress)
|
|
167
|
+
)
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
// in general, wallet should show the decoded information to user for confirmation
|
|
165
171
|
// please overwrite this function for real wallet
|
|
166
172
|
async signUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult> {
|
|
167
|
-
const response = await this.buildUnsignedTx(params)
|
|
173
|
+
const response = await TransactionBuilder.from(this.nodeProvider).buildUnsignedTx(params)
|
|
168
174
|
const signature = await this.signRaw(params.signerAddress, response.txId)
|
|
169
175
|
return { signature, ...response }
|
|
170
176
|
}
|
|
@@ -180,7 +186,7 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
180
186
|
}
|
|
181
187
|
|
|
182
188
|
export abstract class SignerProviderWithMultipleAccounts extends SignerProviderSimple {
|
|
183
|
-
abstract
|
|
189
|
+
abstract setSelectedAccount(address: string): Promise<void>
|
|
184
190
|
|
|
185
191
|
abstract getAccounts(): Promise<Account[]>
|
|
186
192
|
|
|
@@ -204,7 +210,7 @@ export abstract class SignerProviderWithCachedAccounts<T extends Account> extend
|
|
|
204
210
|
private _selectedAccount: T | undefined = undefined
|
|
205
211
|
protected readonly _accounts = new Map<Address, T>()
|
|
206
212
|
|
|
207
|
-
|
|
213
|
+
protected unsafeGetSelectedAccount(): Promise<T> {
|
|
208
214
|
if (this._selectedAccount === undefined) {
|
|
209
215
|
throw Error('No account is selected yet')
|
|
210
216
|
} else {
|
|
@@ -212,7 +218,7 @@ export abstract class SignerProviderWithCachedAccounts<T extends Account> extend
|
|
|
212
218
|
}
|
|
213
219
|
}
|
|
214
220
|
|
|
215
|
-
|
|
221
|
+
setSelectedAccount(address: string): Promise<void> {
|
|
216
222
|
const accountOpt = this._accounts.get(address)
|
|
217
223
|
if (accountOpt === undefined) {
|
|
218
224
|
throw Error('The address is not in the accounts')
|
|
@@ -236,23 +242,14 @@ export abstract class SignerProviderWithCachedAccounts<T extends Account> extend
|
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
244
|
|
|
239
|
-
export function verifyHexString(hexString: string, publicKey: string, signature: string): boolean {
|
|
240
|
-
try {
|
|
241
|
-
const key = ec.keyFromPublic(publicKey, 'hex')
|
|
242
|
-
return key.verify(hexString, utils.signatureDecode(ec, signature))
|
|
243
|
-
} catch (error) {
|
|
244
|
-
return false
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
245
|
function extendMessage(message: string): string {
|
|
249
246
|
return 'Alephium Signed Message: ' + message
|
|
250
247
|
}
|
|
251
248
|
|
|
252
|
-
export function verifySignedMessage(message: string, publicKey: string, signature: string): boolean {
|
|
249
|
+
export function verifySignedMessage(message: string, publicKey: string, signature: string, keyType?: KeyType): boolean {
|
|
253
250
|
const extendedMessage = extendMessage(message)
|
|
254
251
|
const messageHash = blake.blake2b(extendedMessage, undefined, 32)
|
|
255
|
-
return
|
|
252
|
+
return utils.verifySignature(utils.binToHex(messageHash), publicKey, signature, keyType)
|
|
256
253
|
}
|
|
257
254
|
|
|
258
255
|
export function toApiDestination(data: Destination): node.Destination {
|
package/src/signer/tx-builder.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { fromApiNumber256, node, NodeProvider, toApiNumber256Optional, toApiToke
|
|
|
21
21
|
import { addressFromPublicKey } from '../utils'
|
|
22
22
|
import { toApiDestinations } from './signer'
|
|
23
23
|
import {
|
|
24
|
+
KeyType,
|
|
24
25
|
SignDeployContractTxParams,
|
|
25
26
|
SignDeployContractTxResult,
|
|
26
27
|
SignerAddress,
|
|
@@ -35,8 +36,10 @@ import {
|
|
|
35
36
|
export abstract class TransactionBuilder {
|
|
36
37
|
abstract get nodeProvider(): NodeProvider
|
|
37
38
|
|
|
38
|
-
static
|
|
39
|
-
|
|
39
|
+
static from(nodeProvider: NodeProvider): TransactionBuilder
|
|
40
|
+
static from(baseUrl: string, apiKey?: string): TransactionBuilder
|
|
41
|
+
static from(param0: string | NodeProvider, param1?: string): TransactionBuilder {
|
|
42
|
+
const nodeProvider = typeof param0 === 'string' ? new NodeProvider(param0, param1) : (param0 as NodeProvider)
|
|
40
43
|
return new (class extends TransactionBuilder {
|
|
41
44
|
get nodeProvider(): NodeProvider {
|
|
42
45
|
return nodeProvider
|
|
@@ -44,8 +47,8 @@ export abstract class TransactionBuilder {
|
|
|
44
47
|
})()
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
private static validatePublicKey(params: SignerAddress, publicKey: string) {
|
|
48
|
-
const address = addressFromPublicKey(publicKey)
|
|
50
|
+
private static validatePublicKey(params: SignerAddress, publicKey: string, keyType?: KeyType) {
|
|
51
|
+
const address = addressFromPublicKey(publicKey, keyType)
|
|
49
52
|
if (address !== params.signerAddress) {
|
|
50
53
|
throw new Error('Unmatched public key')
|
|
51
54
|
}
|
|
@@ -55,11 +58,12 @@ export abstract class TransactionBuilder {
|
|
|
55
58
|
params: SignTransferTxParams,
|
|
56
59
|
publicKey: string
|
|
57
60
|
): Promise<Omit<SignTransferTxResult, 'signature'>> {
|
|
58
|
-
TransactionBuilder.validatePublicKey(params, publicKey)
|
|
61
|
+
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType)
|
|
59
62
|
|
|
60
63
|
const { destinations, gasPrice, ...rest } = params
|
|
61
64
|
const data: node.BuildTransaction = {
|
|
62
65
|
fromPublicKey: publicKey,
|
|
66
|
+
fromPublicKeyType: params.signerKeyType,
|
|
63
67
|
destinations: toApiDestinations(destinations),
|
|
64
68
|
gasPrice: toApiNumber256Optional(gasPrice),
|
|
65
69
|
...rest
|
|
@@ -72,11 +76,12 @@ export abstract class TransactionBuilder {
|
|
|
72
76
|
params: SignDeployContractTxParams,
|
|
73
77
|
publicKey: string
|
|
74
78
|
): Promise<Omit<SignDeployContractTxResult, 'signature'>> {
|
|
75
|
-
TransactionBuilder.validatePublicKey(params, publicKey)
|
|
79
|
+
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType)
|
|
76
80
|
|
|
77
81
|
const { initialAttoAlphAmount, initialTokenAmounts, issueTokenAmount, gasPrice, ...rest } = params
|
|
78
82
|
const data: node.BuildDeployContractTx = {
|
|
79
83
|
fromPublicKey: publicKey,
|
|
84
|
+
fromPublicKeyType: params.signerKeyType,
|
|
80
85
|
initialAttoAlphAmount: toApiNumber256Optional(initialAttoAlphAmount),
|
|
81
86
|
initialTokenAmounts: toApiTokens(initialTokenAmounts),
|
|
82
87
|
issueTokenAmount: toApiNumber256Optional(issueTokenAmount),
|
|
@@ -92,11 +97,12 @@ export abstract class TransactionBuilder {
|
|
|
92
97
|
params: SignExecuteScriptTxParams,
|
|
93
98
|
publicKey: string
|
|
94
99
|
): Promise<Omit<SignExecuteScriptTxResult, 'signature'>> {
|
|
95
|
-
TransactionBuilder.validatePublicKey(params, publicKey)
|
|
100
|
+
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType)
|
|
96
101
|
|
|
97
102
|
const { attoAlphAmount, tokens, gasPrice, ...rest } = params
|
|
98
103
|
const data: node.BuildExecuteScriptTx = {
|
|
99
104
|
fromPublicKey: publicKey,
|
|
105
|
+
fromPublicKeyType: params.signerKeyType,
|
|
100
106
|
attoAlphAmount: toApiNumber256Optional(attoAlphAmount),
|
|
101
107
|
tokens: toApiTokens(tokens),
|
|
102
108
|
gasPrice: toApiNumber256Optional(gasPrice),
|
package/src/signer/types.ts
CHANGED
|
@@ -33,18 +33,22 @@ export interface Destination {
|
|
|
33
33
|
}
|
|
34
34
|
assertType<Eq<keyof Destination, keyof node.Destination>>
|
|
35
35
|
|
|
36
|
+
export type KeyType = 'default' | 'bip340-schnorr'
|
|
37
|
+
|
|
36
38
|
export interface Account {
|
|
39
|
+
keyType: KeyType
|
|
37
40
|
address: string
|
|
38
41
|
group: number
|
|
39
42
|
publicKey: string
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export type SignerAddress = { signerAddress: string }
|
|
43
|
-
type TxBuildParams<T> = Omit<T, 'fromPublicKey' | 'targetBlockHash'> & SignerAddress
|
|
45
|
+
export type SignerAddress = { signerAddress: string; signerKeyType?: KeyType }
|
|
46
|
+
type TxBuildParams<T> = Omit<T, 'fromPublicKey' | 'fromPublicKeyType' | 'targetBlockHash'> & SignerAddress
|
|
44
47
|
type SignResult<T> = Omit<T, 'gasPrice'> & { signature: string; gasPrice: Number256 }
|
|
45
48
|
|
|
46
49
|
export interface SignTransferTxParams {
|
|
47
50
|
signerAddress: string
|
|
51
|
+
signerKeyType?: KeyType
|
|
48
52
|
destinations: Destination[]
|
|
49
53
|
utxos?: OutputRef[]
|
|
50
54
|
gasAmount?: number
|
|
@@ -64,6 +68,7 @@ assertType<Eq<SignTransferTxResult, SignResult<node.BuildTransactionResult>>>()
|
|
|
64
68
|
|
|
65
69
|
export interface SignDeployContractTxParams {
|
|
66
70
|
signerAddress: string
|
|
71
|
+
signerKeyType?: KeyType
|
|
67
72
|
bytecode: string
|
|
68
73
|
initialAttoAlphAmount?: Number256
|
|
69
74
|
initialTokenAmounts?: Token[]
|
|
@@ -91,6 +96,7 @@ assertType<
|
|
|
91
96
|
|
|
92
97
|
export interface SignExecuteScriptTxParams {
|
|
93
98
|
signerAddress: string
|
|
99
|
+
signerKeyType?: KeyType
|
|
94
100
|
bytecode: string
|
|
95
101
|
attoAlphAmount?: Number256
|
|
96
102
|
tokens?: Token[]
|
|
@@ -115,6 +121,7 @@ assertType<
|
|
|
115
121
|
|
|
116
122
|
export interface SignUnsignedTxParams {
|
|
117
123
|
signerAddress: string
|
|
124
|
+
signerKeyType?: KeyType
|
|
118
125
|
unsignedTx: string
|
|
119
126
|
}
|
|
120
127
|
assertType<Eq<SignUnsignedTxParams, { unsignedTx: string } & SignerAddress>>()
|
|
@@ -131,6 +138,7 @@ assertType<Eq<SignUnsignedTxResult, SignTransferTxResult>>
|
|
|
131
138
|
|
|
132
139
|
export interface SignMessageParams {
|
|
133
140
|
signerAddress: string
|
|
141
|
+
signerKeyType?: KeyType
|
|
134
142
|
message: string
|
|
135
143
|
}
|
|
136
144
|
assertType<Eq<SignMessageParams, { message: string } & SignerAddress>>()
|
|
@@ -154,10 +162,3 @@ export interface EnableOptionsBase {
|
|
|
154
162
|
networkId: string
|
|
155
163
|
onDisconnected: () => Promise<void>
|
|
156
164
|
}
|
|
157
|
-
|
|
158
|
-
// Transaction Params for InteractiveSignerProvider
|
|
159
|
-
export type ExtSignTransferTxParams = SignTransferTxParams & { networkId: string }
|
|
160
|
-
export type ExtSignDeployContractTxParams = SignDeployContractTxParams & { networkId: string }
|
|
161
|
-
export type ExtSignExecuteScriptTxParams = SignExecuteScriptTxParams & { networkId: string }
|
|
162
|
-
export type ExtSignUnsignedTxParams = SignUnsignedTxParams & { networkId: string }
|
|
163
|
-
export type ExtSignMessageParams = SignMessageParams & { networkId: string }
|
|
@@ -17,22 +17,17 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import * as utils from '../utils'
|
|
20
|
-
import {
|
|
20
|
+
import { KeyType } from '../signer'
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export function transactionSign(txHash: string, privateKey: string): string {
|
|
25
|
-
const keyPair = ec.keyFromPrivate(privateKey)
|
|
26
|
-
const signature = keyPair.sign(txHash)
|
|
27
|
-
|
|
28
|
-
return utils.encodeSignature(signature)
|
|
22
|
+
export function transactionSign(txId: string, privateKey: string, keyType?: KeyType): string {
|
|
23
|
+
return utils.sign(txId, privateKey, keyType)
|
|
29
24
|
}
|
|
30
25
|
|
|
31
|
-
export function transactionVerifySignature(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
export function transactionVerifySignature(
|
|
27
|
+
txId: string,
|
|
28
|
+
publicKey: string,
|
|
29
|
+
signature: string,
|
|
30
|
+
keyType?: KeyType
|
|
31
|
+
): boolean {
|
|
32
|
+
return utils.verifySignature(txId, publicKey, signature, keyType)
|
|
38
33
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
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 { ec as EC } from 'elliptic'
|
|
20
|
+
import { binToHex, encodeSignature, hexToBinUnsafe, signatureDecode } from '..'
|
|
21
|
+
import { KeyType } from '../signer'
|
|
22
|
+
import * as necc from '@noble/secp256k1'
|
|
23
|
+
import { createHash, createHmac } from 'crypto'
|
|
24
|
+
|
|
25
|
+
const ec = new EC('secp256k1')
|
|
26
|
+
|
|
27
|
+
necc.utils.sha256Sync = (...messages: Uint8Array[]): Uint8Array => {
|
|
28
|
+
const sha256 = createHash('sha256')
|
|
29
|
+
for (const message of messages) sha256.update(message)
|
|
30
|
+
return sha256.digest()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
necc.utils.hmacSha256Sync = (key: Uint8Array, ...messages: Uint8Array[]): Uint8Array => {
|
|
34
|
+
const hash = createHmac('sha256', Buffer.from(key))
|
|
35
|
+
messages.forEach((m) => hash.update(m))
|
|
36
|
+
return Uint8Array.from(hash.digest())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// hash has to be 32 bytes
|
|
40
|
+
export function sign(hash: string, privateKey: string, _keyType?: KeyType): string {
|
|
41
|
+
const keyType = _keyType ?? 'default'
|
|
42
|
+
|
|
43
|
+
if (keyType === 'default') {
|
|
44
|
+
const key = ec.keyFromPrivate(privateKey)
|
|
45
|
+
const signature = key.sign(hash)
|
|
46
|
+
return encodeSignature(signature)
|
|
47
|
+
} else {
|
|
48
|
+
const signature = necc.schnorr.signSync(hexToBinUnsafe(hash), hexToBinUnsafe(privateKey))
|
|
49
|
+
return binToHex(signature)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function verifySignature(hash: string, publicKey: string, signature: string, _keyType?: KeyType): boolean {
|
|
54
|
+
const keyType = _keyType ?? 'default'
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
if (keyType === 'default') {
|
|
58
|
+
const key = ec.keyFromPublic(publicKey, 'hex')
|
|
59
|
+
return key.verify(hash, signatureDecode(ec, signature))
|
|
60
|
+
} else {
|
|
61
|
+
return necc.schnorr.verifySync(hexToBinUnsafe(signature), hexToBinUnsafe(hash), hexToBinUnsafe(publicKey))
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { Buffer } from 'buffer/'
|
|
|
24
24
|
|
|
25
25
|
import { TOTAL_NUMBER_OF_GROUPS } from '../constants'
|
|
26
26
|
import djb2 from './djb2'
|
|
27
|
+
import { KeyType } from '../signer'
|
|
27
28
|
|
|
28
29
|
const ec = new EC('secp256k1')
|
|
29
30
|
|
|
@@ -157,20 +158,35 @@ export function binToHex(bin: Uint8Array): string {
|
|
|
157
158
|
return Buffer.from(bin).toString('hex')
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
export function groupOfPrivateKey(privateKey: string): number {
|
|
161
|
-
return groupOfAddress(addressFromPublicKey(publicKeyFromPrivateKey(privateKey)))
|
|
161
|
+
export function groupOfPrivateKey(privateKey: string, keyType?: KeyType): number {
|
|
162
|
+
return groupOfAddress(addressFromPublicKey(publicKeyFromPrivateKey(privateKey, keyType), keyType))
|
|
162
163
|
}
|
|
163
164
|
|
|
164
|
-
export function publicKeyFromPrivateKey(privateKey: string): string {
|
|
165
|
-
const
|
|
166
|
-
|
|
165
|
+
export function publicKeyFromPrivateKey(privateKey: string, _keyType?: KeyType): string {
|
|
166
|
+
const keyType = _keyType ?? 'default'
|
|
167
|
+
|
|
168
|
+
if (keyType === 'default') {
|
|
169
|
+
const key = ec.keyFromPrivate(privateKey)
|
|
170
|
+
return key.getPublic(true, 'hex')
|
|
171
|
+
} else {
|
|
172
|
+
return ec.g.mul(new BN(privateKey, 16)).encode('hex', true).slice(2)
|
|
173
|
+
}
|
|
167
174
|
}
|
|
168
175
|
|
|
169
|
-
export function addressFromPublicKey(publicKey: string): string {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
176
|
+
export function addressFromPublicKey(publicKey: string, _keyType?: KeyType): string {
|
|
177
|
+
const keyType = _keyType ?? 'default'
|
|
178
|
+
|
|
179
|
+
if (keyType === 'default') {
|
|
180
|
+
const addressType = Buffer.from([AddressType.P2PKH])
|
|
181
|
+
const hash = Buffer.from(blake.blake2b(Buffer.from(publicKey, 'hex'), undefined, 32))
|
|
182
|
+
const bytes = Buffer.concat([addressType, hash])
|
|
183
|
+
return bs58.encode(bytes)
|
|
184
|
+
} else {
|
|
185
|
+
const lockupScript = Buffer.from(`0101000000000458144020${publicKey}8685`, 'hex')
|
|
186
|
+
const lockupScriptHash = blake.blake2b(lockupScript, undefined, 32)
|
|
187
|
+
const addressType = Buffer.from([AddressType.P2SH])
|
|
188
|
+
return bs58.encode(Buffer.concat([addressType, lockupScriptHash]))
|
|
189
|
+
}
|
|
174
190
|
}
|
|
175
191
|
|
|
176
192
|
export function addressFromContractId(contractId: string): string {
|