@@ -1848,122 +1848,35 @@ describe('V2 Wallet:', function () {
18481848
18491849 response . isDone ( ) . should . be . true ( ) ;
18501850 } ) ;
1851-
1852- it ( 'should preserve server-returned buildParams on prebuild result' , async function ( ) {
1853- const serverBuildParams = {
1854- recipients : [ { address : 'addr1' , amount : '5000' } ] ,
1855- feeRate : 10000 ,
1856- } ;
1857- const params = { offlineVerification : true } ;
1858- nock ( bgUrl )
1859- . post ( `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/build` , tbtcHotWalletDefaultParams )
1860- . query ( params )
1861- . reply ( 200 , { buildParams : serverBuildParams } ) ;
1862- const blockHeight = 100 ;
1863- sinon . stub ( basecoin , 'getLatestBlockHeight' ) . resolves ( blockHeight ) ;
1864- sinon . stub ( basecoin , 'postProcessPrebuild' ) . callsFake ( ( params ) => Promise . resolve ( params ) ) ;
1865- const txPrebuild = await wallet . prebuildTransaction ( { ...params , reqId : reqId } ) ;
1866- should . exist ( txPrebuild . buildParams ) ;
1867- txPrebuild . buildParams ! . should . deepEqual ( serverBuildParams ) ;
1868- } ) ;
1869-
1870- it ( 'should fall back to request params when server does not return buildParams' , async function ( ) {
1871- const params = { offlineVerification : true } ;
1872- nock ( bgUrl )
1873- . post ( `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/build` , tbtcHotWalletDefaultParams )
1874- . query ( params )
1875- . reply ( 200 , { } ) ;
1876- const blockHeight = 100 ;
1877- sinon . stub ( basecoin , 'getLatestBlockHeight' ) . resolves ( blockHeight ) ;
1878- sinon . stub ( basecoin , 'postProcessPrebuild' ) . callsFake ( ( params ) => Promise . resolve ( params ) ) ;
1879- const txPrebuild = await wallet . prebuildTransaction ( { ...params , reqId : reqId } ) ;
1880- should . exist ( txPrebuild . buildParams ) ;
1881- txPrebuild . buildParams ! . should . deepEqual ( tbtcHotWalletDefaultParams ) ;
1882- } ) ;
18831851 } ) ;
18841852
1885- describe ( 'sendMany buildParams pass-through for UTXO coins' , function ( ) {
1886- it ( 'should include recipients from server buildParams in /tx/send request body' , async function ( ) {
1887- const recipients = [ { address : 'addr1' , amount : '5000' } ] ;
1888- const serverBuildParams = { recipients, feeRate : 10000 } ;
1889- const prebuildReturn = { txHex : 'deadbeef' , buildParams : serverBuildParams } ;
1890- sinon . stub ( wallet , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
1891- sinon . stub ( basecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
1892-
1893- const path = `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/send` ;
1894- const sendNock = nock ( bgUrl )
1895- . post ( path , _ . matches ( { txHex : 'deadbeef' , recipients, feeRate : 10000 } ) )
1896- . reply ( 200 , { status : 'signed' } ) ;
1897-
1898- const result = await wallet . sendMany ( { recipients } ) ;
1899- sendNock . isDone ( ) . should . be . true ( ) ;
1900- result . should . have . property ( 'status' , 'signed' ) ;
1901- } ) ;
1902-
1903- it ( 'should include RBF fields from server buildParams in /tx/send request body' , async function ( ) {
1904- const recipients = [ { address : 'addr1' , amount : '5000' } ] ;
1905- const serverBuildParams = {
1906- recipients,
1907- rbfTxIds : [ 'txid1' ] ,
1908- maxFee : 50000 ,
1909- feeMultiplier : 2 ,
1910- } ;
1911- const prebuildReturn = { txHex : 'deadbeef' , buildParams : serverBuildParams } ;
1912- sinon . stub ( wallet , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
1913- sinon . stub ( basecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
1914-
1915- const path = `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/send` ;
1916- const sendNock = nock ( bgUrl )
1917- . post ( path , _ . matches ( { txHex : 'deadbeef' , rbfTxIds : [ 'txid1' ] , maxFee : 50000 , feeMultiplier : 2 } ) )
1918- . reply ( 200 , { status : 'signed' } ) ;
1919-
1920- const result = await wallet . sendMany ( { recipients } ) ;
1921- sendNock . isDone ( ) . should . be . true ( ) ;
1922- result . should . have . property ( 'status' , 'signed' ) ;
1923- } ) ;
1924-
1925- it ( 'should work when server returns no buildParams in build response' , async function ( ) {
1853+ describe ( 'sendMany includes user-provided recipients at top level in /tx/send' , function ( ) {
1854+ it ( 'should include top-level recipients from user params for UTXO coins' , async function ( ) {
19261855 const recipients = [ { address : 'addr1' , amount : '5000' } ] ;
19271856 const prebuildReturn = { txHex : 'deadbeef' } ;
19281857 sinon . stub ( wallet , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
19291858 sinon . stub ( basecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
19301859
19311860 const path = `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/send` ;
19321861 const sendNock = nock ( bgUrl )
1933- . post ( path , _ . matches ( { txHex : 'deadbeef' } ) )
1862+ . post ( path , ( body ) => {
1863+ // recipients from user params must appear at top level via selectParams
1864+ return (
1865+ body . recipients !== undefined &&
1866+ body . recipients [ 0 ] . address === recipients [ 0 ] . address &&
1867+ body . txHex === 'deadbeef'
1868+ ) ;
1869+ } )
19341870 . reply ( 200 , { status : 'signed' } ) ;
19351871
19361872 const result = await wallet . sendMany ( { recipients } ) ;
19371873 sendNock . isDone ( ) . should . be . true ( ) ;
19381874 result . should . have . property ( 'status' , 'signed' ) ;
19391875 } ) ;
19401876
1941- it ( 'should let explicit user params override server buildParams' , async function ( ) {
1942- const userRecipients = [ { address : 'user-addr' , amount : '9999' } ] ;
1943- const serverRecipients = [ { address : 'server-addr' , amount : '5000' } ] ;
1944- const serverBuildParams = { recipients : serverRecipients , feeRate : 10000 } ;
1945- const prebuildReturn = { txHex : 'deadbeef' , buildParams : serverBuildParams } ;
1946- sinon . stub ( wallet , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
1947- sinon . stub ( basecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
1948-
1949- const path = `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/send` ;
1950- const sendNock = nock ( bgUrl )
1951- . post ( path , _ . matches ( { txHex : 'deadbeef' , recipients : userRecipients } ) )
1952- . reply ( 200 , { status : 'signed' } ) ;
1953-
1954- const result = await wallet . sendMany ( { recipients : userRecipients } ) ;
1955- sendNock . isDone ( ) . should . be . true ( ) ;
1956- result . should . have . property ( 'status' , 'signed' ) ;
1957- } ) ;
1958- } ) ;
1959-
1960- describe ( 'sendMany buildParams pass-through for account-based coins' , function ( ) {
1961- let ethBasecoin ;
1962- let ethWalletForBuildParams : Wallet ;
1963-
1964- before ( function ( ) {
1965- ethBasecoin = bitgo . coin ( 'teth' ) ;
1966- ethWalletForBuildParams = new Wallet ( bitgo , ethBasecoin , {
1877+ it ( 'should include top-level recipients alongside halfSigned for account-based coins' , async function ( ) {
1878+ const ethBasecoin = bitgo . coin ( 'teth' ) ;
1879+ const ethWalletLocal = new Wallet ( bitgo , ethBasecoin , {
19671880 id : '598f606cd8fc24710d2ebadb1d9459bb' ,
19681881 coin : 'teth' ,
19691882 keys : [
@@ -1974,27 +1887,22 @@ describe('V2 Wallet:', function () {
19741887 multisigType : 'onchain' ,
19751888 type : 'hot' ,
19761889 } ) ;
1977- } ) ;
1978-
1979- it ( 'should include top-level recipients alongside halfSigned in /tx/send for ETH' , async function ( ) {
19801890 const recipients = [ { address : '0x5208d8e80c6d1aef9be37b4bd19a9cf75ed93dc8' , amount : '200000000000000' } ] ;
1981- const serverBuildParams = { recipients } ;
19821891 const prebuildReturn = {
19831892 halfSigned : {
19841893 recipients,
19851894 txHex : '0xdeadbeef' ,
19861895 expireTime : 1234567890 ,
19871896 contractSequenceId : 1001 ,
19881897 } ,
1989- buildParams : serverBuildParams ,
19901898 } ;
1991- sinon . stub ( ethWalletForBuildParams , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
1899+ sinon . stub ( ethWalletLocal , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
19921900 sinon . stub ( ethBasecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
19931901
1994- const path = `/api/v2/${ ethWalletForBuildParams . coin ( ) } /wallet/${ ethWalletForBuildParams . id ( ) } /tx/send` ;
1902+ const path = `/api/v2/${ ethWalletLocal . coin ( ) } /wallet/${ ethWalletLocal . id ( ) } /tx/send` ;
19951903 const sendNock = nock ( bgUrl )
19961904 . post ( path , ( body ) => {
1997- // recipients must be at top level (not just inside halfSigned)
1905+ // recipients from user params must be at top level (not just inside halfSigned)
19981906 return (
19991907 body . recipients !== undefined &&
20001908 body . recipients [ 0 ] . address === recipients [ 0 ] . address &&
@@ -2003,66 +1911,30 @@ describe('V2 Wallet:', function () {
20031911 } )
20041912 . reply ( 200 , { status : 'signed' } ) ;
20051913
2006- const result = await ethWalletForBuildParams . sendMany ( { recipients } ) ;
1914+ const result = await ethWalletLocal . sendMany ( { recipients } ) ;
20071915 sendNock . isDone ( ) . should . be . true ( ) ;
20081916 result . should . have . property ( 'status' , 'signed' ) ;
20091917 } ) ;
20101918
2011- it ( 'should include top-level recipients from selectParams even without server buildParams for ETH' , async function ( ) {
2012- const recipients = [ { address : '0x5208d8e80c6d1aef9be37b4bd19a9cf75ed93dc8' , amount : '200000000000000' } ] ;
2013- // No buildParams — simulates old server that doesn't return buildParams
2014- const prebuildReturn = {
2015- halfSigned : {
2016- recipients,
2017- txHex : '0xdeadbeef' ,
2018- expireTime : 1234567890 ,
2019- contractSequenceId : 1001 ,
2020- } ,
2021- } ;
2022- sinon . stub ( ethWalletForBuildParams , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
2023- sinon . stub ( ethBasecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
1919+ it ( 'should not forward server-returned buildParams to /tx/send' , async function ( ) {
1920+ const userRecipients = [ { address : 'user-addr' , amount : '9999' } ] ;
1921+ const prebuildReturn = { txHex : 'deadbeef' } ;
1922+ sinon . stub ( wallet , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
1923+ sinon . stub ( basecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
20241924
2025- const path = `/api/v2/${ ethWalletForBuildParams . coin ( ) } /wallet/${ ethWalletForBuildParams . id ( ) } /tx/send` ;
1925+ const path = `/api/v2/${ wallet . coin ( ) } /wallet/${ wallet . id ( ) } /tx/send` ;
20261926 const sendNock = nock ( bgUrl )
20271927 . post ( path , ( body ) => {
2028- // recipients should still be at top level via selectParams (user's original params)
1928+ // only user-provided recipients should appear, no server buildParams key
20291929 return (
20301930 body . recipients !== undefined &&
2031- body . recipients [ 0 ] . address === recipients [ 0 ] . address &&
2032- body . halfSigned ! == undefined
1931+ body . recipients [ 0 ] . address === 'user-addr' &&
1932+ body . buildParams = == undefined
20331933 ) ;
20341934 } )
20351935 . reply ( 200 , { status : 'signed' } ) ;
20361936
2037- const result = await ethWalletForBuildParams . sendMany ( { recipients } ) ;
2038- sendNock . isDone ( ) . should . be . true ( ) ;
2039- result . should . have . property ( 'status' , 'signed' ) ;
2040- } ) ;
2041-
2042- it ( 'should include eip1559 and nonce from server buildParams at top level for ETH' , async function ( ) {
2043- const recipients = [ { address : '0x5208d8e80c6d1aef9be37b4bd19a9cf75ed93dc8' , amount : '200000000000000' } ] ;
2044- const eip1559 = { maxPriorityFeePerGas : '57500000' , maxFeePerGas : '510214356' } ;
2045- const serverBuildParams = { recipients, nonce : 42 , memo : { value : 'test' } } ;
2046- const prebuildReturn = {
2047- halfSigned : {
2048- recipients,
2049- txHex : '0xdeadbeef' ,
2050- eip1559,
2051- contractSequenceId : 3371928 ,
2052- } ,
2053- buildParams : serverBuildParams ,
2054- } ;
2055- sinon . stub ( ethWalletForBuildParams , 'prebuildAndSignTransaction' ) . resolves ( prebuildReturn ) ;
2056- sinon . stub ( ethBasecoin , 'getExtraPrebuildParams' ) . resolves ( { } ) ;
2057-
2058- const path = `/api/v2/${ ethWalletForBuildParams . coin ( ) } /wallet/${ ethWalletForBuildParams . id ( ) } /tx/send` ;
2059- const sendNock = nock ( bgUrl )
2060- . post ( path , ( body ) => {
2061- return body . recipients !== undefined && body . halfSigned !== undefined && body . nonce === 42 ;
2062- } )
2063- . reply ( 200 , { status : 'signed' } ) ;
2064-
2065- const result = await ethWalletForBuildParams . sendMany ( { recipients } ) ;
1937+ const result = await wallet . sendMany ( { recipients : userRecipients } ) ;
20661938 sendNock . isDone ( ) . should . be . true ( ) ;
20671939 result . should . have . property ( 'status' , 'signed' ) ;
20681940 } ) ;
0 commit comments