1
- import { SHA3 } from 'sha3'
2
1
import { AxiosInstance } from "axios"
3
- import { getSignPIN } from "../mixin/sign"
4
- import { BigNumber } from 'bignumber.js'
5
2
import {
6
- Keystore ,
7
- CollectiblesClientRequest , CollectiblesRequest , CollectiblesUTXO ,
8
- CollectiblesAction , RawTransactionInput , Transaction , GhostInput , GhostKeys ,
3
+ Keystore , TransactionInput , GhostInput , GhostKeys ,
4
+ CollectiblesClientRequest , CollectiblesParams , CollectibleToken , RawCollectibleInput , Transaction , CollectibleAction , CollectibleRequest , CollectibleOutput ,
9
5
} from "../types"
10
- import { dumpTransaction } from '../mixin/dump_transacion'
11
-
12
- const TxVersion = 0x02
13
-
14
- const OperatorSum = 0xfe
15
- const OperatorCmp = 0xff
6
+ import { DumpOutputFromGhostKey , dumpTransaction } from '../mixin/dump_transacion'
7
+ import { hashMember } from '../mixin/tools'
8
+ import { TxVersion } from '../mixin/encoder'
9
+ import { getSignPIN } from '../mixin/sign'
10
+ import { buildMintCollectibleMemo } from '../mixin/nfo'
16
11
12
+ const MintAssetID = "c94ac88f-4671-3976-b60a-09064f1811e8"
13
+ const MintMinimumCost = "0.001"
14
+ const GroupMembers = [
15
+ "4b188942-9fb0-4b99-b4be-e741a06d1ebf" ,
16
+ "dd655520-c919-4349-822f-af92fabdbdf4" ,
17
+ "047061e6-496d-4c35-b06b-b0424a8a400d" ,
18
+ "acf65344-c778-41ee-bacb-eb546bacfb9f" ,
19
+ "a51006d0-146b-4b32-a2ce-7defbf0d7735" ,
20
+ "cf4abd9c-2cfa-4b5a-b1bd-e2b61a83fabd" ,
21
+ "50115496-7247-4e2c-857b-ec8680756bee" ,
22
+ ]
23
+ const GroupThreshold = 5
17
24
export class CollectiblesClient implements CollectiblesClientRequest {
18
25
keystore ! : Keystore
19
26
request ! : AxiosInstance
20
- readGhostKeys ! : ( receivers : string [ ] , index : number ) => Promise < GhostKeys >
21
27
batchReadGhostKeys ! : ( inputs : GhostInput [ ] ) => Promise < GhostKeys [ ] >
22
-
23
- readCollectible ( id : string ) : Promise < CollectiblesUTXO [ ] > {
24
- return this . request . get ( `/collectibles/tokens/${ id } ` )
28
+ newMintCollectibleTransferInput ( p : CollectiblesParams ) : TransactionInput {
29
+ const { trace_id, collection_id, token_id, content } = p
30
+ if ( ! trace_id || ! collection_id || ! token_id || ! content ) throw new Error ( "Missing parameters" )
31
+ let input : TransactionInput = {
32
+ asset_id : MintAssetID ,
33
+ amount : MintMinimumCost ,
34
+ trace_id,
35
+ memo : buildMintCollectibleMemo ( collection_id , token_id , content ) ,
36
+ opponent_multisig : {
37
+ receivers : GroupMembers ,
38
+ threshold : GroupThreshold ,
39
+ }
40
+ }
41
+ return input
42
+ }
43
+ readCollectibleToken ( id : string ) : Promise < CollectibleToken > {
44
+ return this . request . get ( `/collectibles/tokens/` + id )
25
45
}
26
- readCollectibleOutputs ( members : string [ ] , threshold : number , offset : string , limit : number ) : Promise < CollectiblesUTXO [ ] > {
27
- if ( members . length > 0 && threshold < 1 || threshold > members . length ) return Promise . reject ( new Error ( "Invalid threshold or members" ) )
28
- const params : any = { threshold : Number ( threshold ) , offset, limit }
29
- params . members = hashMember ( members )
30
- return this . request . get ( `/collectibles/outputs` , { params } )
46
+ readCollectibleOutputs ( _members : string [ ] , threshold : number , offset : string , limit : number ) : Promise < CollectibleOutput [ ] > {
47
+ const members = hashMember ( _members )
48
+ return this . request . get ( `/collectibles/outputs` , { params : { members, threshold, offset, limit } } )
49
+ }
50
+ async makeCollectibleTransactionRaw ( txInput : RawCollectibleInput ) : Promise < string > {
51
+ const { token, output, receivers, threshold } = txInput
52
+ const tx : Transaction = {
53
+ version : TxVersion ,
54
+ asset : token . mixin_id ! ,
55
+ extra : token . nfo ! ,
56
+ inputs : [
57
+ {
58
+ hash : output . transaction_hash ! ,
59
+ index : output . output_index !
60
+ }
61
+ ]
62
+ }
63
+ const ghostInputs = await this . batchReadGhostKeys ( [ {
64
+ receivers,
65
+ index : 0 ,
66
+ hint : output . output_id !
67
+ } ] )
68
+ tx . outputs = [ DumpOutputFromGhostKey ( ghostInputs [ 0 ] , output . amount ! , threshold ) ]
69
+ return dumpTransaction ( tx )
31
70
}
32
- createCollectible ( action : CollectiblesAction , raw : string ) : Promise < CollectiblesRequest > {
71
+ createCollectibleRequest ( action : CollectibleAction , raw : string ) : Promise < CollectibleRequest > {
33
72
return this . request . post ( `/collectibles/requests` , { action, raw } )
34
73
}
35
- signCollectible ( request_id : string , pin ?: string ) : Promise < CollectiblesRequest > {
74
+ signCollectibleRequest ( requestId : string , pin ?: string ) : Promise < CollectibleRequest > {
36
75
pin = getSignPIN ( this . keystore , pin )
37
- return this . request . post ( `/collectibles/requests/${ request_id } /sign` , { pin } )
76
+ return this . request . post ( `/collectibles/requests/${ requestId } /sign` , { pin } )
38
77
}
39
- cancelCollectible ( request_id : string ) : Promise < void > {
40
- return this . request . post ( `/collectibles/requests/${ request_id } /cancel` )
78
+ cancelCollectibleRequest ( requestId : string ) : Promise < void > {
79
+ return this . request . post ( `/collectibles/requests/${ requestId } /cancel` )
41
80
}
42
- unlockCollectible ( request_id : string , pin : string ) : Promise < void > {
81
+ unlockCollectibleRequest ( requestId : string , pin ? : string ) : Promise < void > {
43
82
pin = getSignPIN ( this . keystore , pin )
44
- return this . request . post ( `/collectibles/requests/${ request_id } /unlock` , { pin } )
83
+ return this . request . post ( `/collectibles/requests/${ requestId } /unlock` , { pin } )
45
84
}
46
- async makeCollectiblesTransaction ( txInput : RawTransactionInput ) : Promise < string > {
47
- // validate ...
48
- let { inputs, memo, outputs } = txInput
49
- const tx : Transaction = {
50
- version : TxVersion ,
51
- asset : newHash ( inputs [ 0 ] . asset_id ) ,
52
- extra : Buffer . from ( memo ) . toString ( 'base64' ) ,
53
- inputs : [ ] ,
54
- outputs : [ ]
55
- }
56
- // add input
57
- for ( const input of inputs ) {
58
- tx . inputs ! . push ( {
59
- hash : input . transaction_hash ,
60
- index : input . output_index
61
- } )
62
- }
63
- let change = inputs . reduce ( ( sum , input ) => sum . plus ( input . amount ) , new BigNumber ( 0 ) )
64
- for ( const output of outputs ) change = change . minus ( output . amount )
65
- if ( change . isGreaterThan ( 0 ) ) outputs . push ( { receivers : inputs [ 0 ] . members , threshold : inputs [ 0 ] . threshold , amount : change . toString ( ) } )
66
- const ghostInputs : GhostInput [ ] = [ ]
67
- outputs . forEach ( ( output , idx ) => ghostInputs . push ( { receivers : output . receivers , index : idx , hint : txInput . hint } ) )
68
- // get ghost keys
69
- let ghosts = await this . batchReadGhostKeys ( ghostInputs )
70
- outputs . forEach ( ( output , idx ) => {
71
- const { mask, keys } = ghosts [ idx ]
72
- tx . outputs ! . push ( {
73
- mask,
74
- keys,
75
- amount : Number ( output . amount ) . toFixed ( 8 ) ,
76
- script : Buffer . from ( [ OperatorCmp , OperatorSum , output . threshold ] ) . toString ( 'hex' )
77
- } )
78
- } )
79
- return dumpTransaction ( tx )
80
- }
81
- }
82
-
83
- function hashMember ( ids : string [ ] ) {
84
- ids = ids . sort ( ( a , b ) => a > b ? 1 : - 1 )
85
- return newHash ( ids . join ( '' ) )
86
85
}
87
86
88
- function newHash ( str : string ) {
89
- return new SHA3 ( 256 ) . update ( str ) . digest ( 'hex' )
90
- }
0 commit comments