@@ -6,6 +6,13 @@ import {
66 PostCreateAddress ,
77} from '../../../src/typedRoutes/api/v2/createAddress' ;
88import { assertDecode } from './common' ;
9+ import 'should' ;
10+ import 'should-http' ;
11+ import 'should-sinon' ;
12+ import * as sinon from 'sinon' ;
13+ import * as request from 'supertest' ;
14+ import { BitGo } from 'bitgo' ;
15+ import { app as expressApp } from '../../../src/expressApp' ;
916
1017/**
1118 * Helper function to extract path parameter names from a route path
@@ -26,6 +33,144 @@ function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
2633}
2734
2835describe ( 'CreateAddress codec tests' , function ( ) {
36+ describe ( 'createAddress' , function ( ) {
37+ let agent : request . SuperAgentTest ;
38+
39+ const walletId = '68c02f96aa757d9212bd1a536f123456' ;
40+ const coin = 'tbtc' ;
41+
42+ const mockResponse = {
43+ id : '68ed4dbfe664aa98d171ac0f524ef111' ,
44+ address : '2N632etYgykMhGrScEN7RpAthg64ACsTL6v' ,
45+ chain : 0 ,
46+ index : 1 ,
47+ coin : 'tbtc' ,
48+ wallet : '68c02f96aa757d9212bd1a536f123456' ,
49+ label : 'My new address' ,
50+ coinSpecific : {
51+ redeemScript :
52+ '522103ebc10ae7ca49f55228fd29dd32eadfcd289fb43082fabb8e0f3bcee9ab09853721039b1a9b93a2e8114d6627753fc37f115e721609b35187d74dc32e5adfa97992402102a704615d8eedaf2e0ff37f7e503615fb6765b8b147a97ac1d930b37e709755dc53ae' ,
53+ } ,
54+ addressType : 'p2sh' ,
55+ keychains : [
56+ {
57+ id : '68c02f94aa757d9212bd19b783deb065' ,
58+ pub : 'xpub661MyMwAqRbcGCSB6BrtvtRzb4Pebi5RLaC8dqZ8Zt2sJsWZ8dj7pXrLRfiGjYAD5PMV23dAxNQww8kggwKZUZtEhcjH1vPDhu4dUihbv2T' ,
59+ ethAddress : '0x23f7b80a5f5dce2bfb9e09d40e37794cc8e2a3be' ,
60+ source : 'user' ,
61+ type : 'independent' ,
62+ encryptedPrv :
63+ '{"iv":"abc123xyz456==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"def789ghi012=","ct":"mockEncryptedPrivateKeyData1234567890"}' ,
64+ } ,
65+ {
66+ id : '68c02f94a36d5167fa49878f9553f40e' ,
67+ pub : 'xpub661MyMwAqRbcFUMUdma6ot9QPBcBDiyJSo3CsyE53hjcZ9RgAH2oxcNViRTv9bUJrHeEiDhL2sLDa9kXgjSwL33Bca3ApQaG7nBJJc5enLr' ,
68+ ethAddress : '0xfb1d696334a2632952ae25aead77be781df91e18' ,
69+ source : 'backup' ,
70+ type : 'independent' ,
71+ encryptedPrv :
72+ '{"iv":"uvw345qrs678==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"jkl901mno234=","ct":"mockEncryptedPrivateKeyDataBackup567890"}' ,
73+ } ,
74+ {
75+ id : '68c02f95aa757d9212bd19e7ee0744e4' ,
76+ pub : 'xpub661MyMwAqRbcFZ1e1eeAuFnu8gBAM1Yd7bJUSEL7TRX3QQ6vbY6B5Uugf8E93eTfvcKRHHZUiqq7WLLerZdFkp2guAVG1Mkuqp6ZZqbQ53u' ,
77+ ethAddress : '0xfad325e7f4b57549ff68395e0d42378046208a71' ,
78+ source : 'bitgo' ,
79+ type : 'independent' ,
80+ isBitGo : true ,
81+ isTrust : false ,
82+ hsmType : 'institutional' ,
83+ } ,
84+ ] ,
85+ } ;
86+
87+ before ( function ( ) {
88+ const args : any = {
89+ debug : false ,
90+ env : 'test' ,
91+ logfile : '/dev/null' ,
92+ } ;
93+
94+ const app = expressApp ( args ) ;
95+ agent = request . agent ( app ) ;
96+ } ) ;
97+
98+ afterEach ( function ( ) {
99+ sinon . restore ( ) ;
100+ } ) ;
101+
102+ it ( 'should successfully create a new wallet address' , async function ( ) {
103+ const requestBody = {
104+ label : 'My new address' ,
105+ chain : 0 ,
106+ allowSkipVerifyAddress : true ,
107+ } ;
108+
109+ // Create mock wallet with createAddress method
110+ const mockWallet = {
111+ createAddress : sinon . stub ( ) . resolves ( mockResponse ) ,
112+ } ;
113+
114+ // Stub the wallets().get() chain
115+ const walletsGetStub = sinon . stub ( ) . resolves ( mockWallet ) ;
116+
117+ const mockWallets = {
118+ get : walletsGetStub ,
119+ } ;
120+
121+ const mockCoin = {
122+ wallets : sinon . stub ( ) . returns ( mockWallets ) ,
123+ } ;
124+
125+ // Stub BitGo.prototype.coin to return our mock coin
126+ const coinStub = sinon . stub ( BitGo . prototype , 'coin' ) . returns ( mockCoin as any ) ;
127+
128+ // Make the request to Express
129+ const result = await agent
130+ . post ( `/api/v2/${ coin } /wallet/${ walletId } /address` )
131+ . set ( 'Authorization' , 'Bearer test_access_token_12345' )
132+ . set ( 'Content-Type' , 'application/json' )
133+ . send ( requestBody ) ;
134+
135+ // Verify the response
136+ assert . strictEqual ( result . status , 200 ) ;
137+ result . body . should . have . property ( 'id' , '68ed4dbfe664aa98d171ac0f524ef111' ) ;
138+ result . body . should . have . property ( 'address' , '2N632etYgykMhGrScEN7RpAthg64ACsTL6v' ) ;
139+ result . body . should . have . property ( 'chain' , 0 ) ;
140+ result . body . should . have . property ( 'index' , 1 ) ;
141+ result . body . should . have . property ( 'coin' , 'tbtc' ) ;
142+ result . body . should . have . property ( 'wallet' , walletId ) ;
143+ result . body . should . have . property ( 'label' , 'My new address' ) ;
144+ result . body . should . have . property ( 'addressType' , 'p2sh' ) ;
145+ result . body . should . have . property ( 'keychains' ) ;
146+ result . body . keychains . should . be . Array ( ) ;
147+ result . body . keychains . should . have . length ( 3 ) ;
148+
149+ // Verify the keychain structure
150+ result . body . keychains [ 0 ] . should . have . property ( 'source' , 'user' ) ;
151+ result . body . keychains [ 1 ] . should . have . property ( 'source' , 'backup' ) ;
152+ result . body . keychains [ 2 ] . should . have . property ( 'source' , 'bitgo' ) ;
153+ result . body . keychains [ 2 ] . should . have . property ( 'isBitGo' , true ) ;
154+
155+ // Verify that the correct BitGoJS methods were called
156+ assert . strictEqual ( coinStub . calledOnceWith ( coin ) , true ) ;
157+ assert . strictEqual ( mockCoin . wallets . calledOnce , true ) ;
158+ assert . strictEqual ( walletsGetStub . calledOnceWith ( { id : walletId } ) , true ) ;
159+ assert . strictEqual (
160+ mockWallet . createAddress . calledOnceWith (
161+ sinon . match ( {
162+ coin : coin ,
163+ id : walletId ,
164+ label : 'My new address' ,
165+ chain : 0 ,
166+ allowSkipVerifyAddress : true ,
167+ } )
168+ ) ,
169+ true
170+ ) ;
171+ } ) ;
172+ } ) ;
173+
29174 describe ( 'CreateAddressParams' , function ( ) {
30175 it ( 'should validate params with required coin and id' , function ( ) {
31176 const validParams = {
0 commit comments