22using BTCPayServer . Plugins . Monero . Services ;
33using BTCPayServer . Rating ;
44using BTCPayServer . Services . Rates ;
5+ using BTCPayServer . Tests ;
56using BTCPayServer . Tests . Mocks ;
67
78using Xunit ;
@@ -17,56 +18,7 @@ public async Task ShouldEnableMoneroPluginSuccessfully()
1718 await using var s = CreatePlaywrightTester ( ) ;
1819 await s . StartAsync ( ) ;
1920
20- if ( s . Server . PayTester . MockRates )
21- {
22- var rateProviderFactory = s . Server . PayTester . GetService < RateProviderFactory > ( ) ;
23- rateProviderFactory . Providers . Clear ( ) ;
24-
25- var coinAverageMock = new MockRateProvider ( ) ;
26- coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 5000m ) ) ) ;
27- coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_EUR" ) , new BidAsk ( 4000m ) ) ) ;
28- coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_BTC" ) , new BidAsk ( 4500m ) ) ) ;
29- rateProviderFactory . Providers . Add ( "coingecko" , coinAverageMock ) ;
30-
31- var kraken = new MockRateProvider ( ) ;
32- kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 0.1m ) ) ) ;
33- kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_USD" ) , new BidAsk ( 0.1m ) ) ) ;
34- kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_BTC" ) , new BidAsk ( 0.1m ) ) ) ;
35- rateProviderFactory . Providers . Add ( "kraken" , kraken ) ;
36- }
37-
38- await s . RegisterNewUser ( true ) ;
39- await s . CreateNewStore ( preferredExchange : "Kraken" ) ;
40- await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
41- await s . Page . Locator ( "input#PrimaryAddress" )
42- . FillAsync (
43- "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
44- await s . Page . Locator ( "input#PrivateViewKey" )
45- . FillAsync ( "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ) ;
46- await s . Page . Locator ( "input#RestoreHeight" ) . FillAsync ( "0" ) ;
47- await s . Page . ClickAsync ( "button[name='command'][value='set-wallet-details']" ) ;
48- var message = await s . Page
49- . GetByText ( "View-only wallet created. The wallet will soon become available." )
50- . InnerTextAsync ( ) ;
51- Assert . Contains ( "View-only wallet created" , message ) ;
52- await s . Page . CheckAsync ( "#Enabled" ) ;
53- await s . Page . SelectOptionAsync ( "#SettlementConfirmationThresholdChoice" , "2" ) ;
54- await s . Page . ClickAsync ( "#SaveButton" ) ;
55-
56- // Set rate provider
57- await s . Page . Locator ( "#menu-item-General" ) . ClickAsync ( ) ;
58- await s . Page . Locator ( "#menu-item-Rates" ) . ClickAsync ( ) ;
59- await s . Page . FillAsync ( "#DefaultCurrencyPairs" , "BTC_USD,XMR_USD,XMR_BTC" ) ;
60- await s . Page . SelectOptionAsync ( "#PrimarySource_PreferredExchange" , "kraken" ) ;
61- await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
62-
63- // Generate a new invoice
64- await s . Page . Locator ( "a.nav-link[href*='invoices']" ) . ClickAsync ( ) ;
65- await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
66- await s . Page . FillAsync ( "#Amount" , "4.20" ) ;
67- await s . Page . FillAsync ( "#BuyerEmail" , "monero@monero.com" ) ;
68- await Task . Delay ( TimeSpan . FromSeconds ( 25 ) ) ; // wallet-rpc needs some time to sync. refactor this later
69- await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
21+ await SetupWalletAndGenerateInvoice ( s ) ;
7022
7123 // View the invoice
7224 var href = await s . Page . Locator ( "a[href^='/i/']" ) . GetAttributeAsync ( "href" ) ;
@@ -104,6 +56,46 @@ await s.Page.Locator("input#PrivateViewKey")
10456 await IntegrationTestUtils . CleanUpAsync ( s ) ;
10557 }
10658
59+ [ Fact ]
60+ public async Task ShouldAdvanceSubaddressIndexWhenOutOfSync ( )
61+ {
62+ await using var s = CreatePlaywrightTester ( ) ;
63+ await s . StartAsync ( ) ;
64+
65+ await SetupWalletAndGenerateInvoice ( s ) ;
66+
67+ await IntegrationTestUtils . CleanUpAsync ( s , false ) ;
68+
69+ MoneroRpcProvider moneroRpcProvider = s . Server . PayTester . GetService < MoneroRpcProvider > ( ) ;
70+ await moneroRpcProvider . WalletRpcClients [ "XMR" ]
71+ . SendCommandAsync < GenerateFromKeysRequest , GenerateFromKeysResponse > ( "generate_from_keys" ,
72+ new GenerateFromKeysRequest
73+ {
74+ PrimaryAddress =
75+ "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ,
76+ PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ,
77+ WalletFileName = "wallet" ,
78+ Password = ""
79+ } ) ;
80+
81+ await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
82+
83+ var invoiceCount = Random . Shared . Next ( 1 , 11 ) ; // 1 to 10 invoices
84+ for ( int i = 0 ; i < invoiceCount ; i ++ )
85+ {
86+ await s . Page . Locator ( "a.nav-link[href*='invoices']" ) . ClickAsync ( ) ;
87+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
88+ await s . Page . FillAsync ( "#Amount" , "4.20" ) ;
89+ await s . Page . FillAsync ( "#BuyerEmail" , $ "monero{ i } @monero.com") ; // make email unique
90+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
91+ }
92+
93+ // Fails to view the last invoice
94+ await s . Page . Locator ( "a[href^='/i/']" ) . GetAttributeAsync ( "href" ) ;
95+
96+ await IntegrationTestUtils . CleanUpAsync ( s ) ;
97+ }
98+
10799 [ Fact ]
108100 public async Task ShouldFailWhenWrongPrimaryAddress ( )
109101 {
@@ -135,20 +127,24 @@ public async Task ShouldFailWhenWalletFileAlreadyExists()
135127 await s . StartAsync ( ) ;
136128
137129 MoneroRpcProvider moneroRpcProvider = s . Server . PayTester . GetService < MoneroRpcProvider > ( ) ;
138- await moneroRpcProvider . WalletRpcClients [ "XMR" ] . SendCommandAsync < GenerateFromKeysRequest , GenerateFromKeysResponse > ( "generate_from_keys" , new GenerateFromKeysRequest
139- {
140- PrimaryAddress = "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ,
141- PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ,
142- WalletFileName = "wallet" ,
143- Password = ""
144- } ) ;
130+ await moneroRpcProvider . WalletRpcClients [ "XMR" ]
131+ . SendCommandAsync < GenerateFromKeysRequest , GenerateFromKeysResponse > ( "generate_from_keys" ,
132+ new GenerateFromKeysRequest
133+ {
134+ PrimaryAddress =
135+ "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ,
136+ PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ,
137+ WalletFileName = "wallet" ,
138+ Password = ""
139+ } ) ;
145140 await moneroRpcProvider . CloseWallet ( "XMR" ) ;
146141
147142 await s . RegisterNewUser ( true ) ;
148143 await s . CreateNewStore ( ) ;
149144 await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
150145 await s . Page . Locator ( "input#PrimaryAddress" )
151- . FillAsync ( "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
146+ . FillAsync (
147+ "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
152148 await s . Page . Locator ( "input#PrivateViewKey" )
153149 . FillAsync ( "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ) ;
154150 await s . Page . Locator ( "input#RestoreHeight" ) . FillAsync ( "0" ) ;
@@ -198,4 +194,58 @@ public async Task ShouldLoadViewWalletWithPasswordOnStartUpIfExists()
198194
199195 await IntegrationTestUtils . CleanUpAsync ( s ) ;
200196 }
197+
198+ static async Task SetupWalletAndGenerateInvoice ( PlaywrightTester s )
199+ {
200+ if ( s . Server . PayTester . MockRates )
201+ {
202+ var rateProviderFactory = s . Server . PayTester . GetService < RateProviderFactory > ( ) ;
203+ rateProviderFactory . Providers . Clear ( ) ;
204+
205+ var coinAverageMock = new MockRateProvider ( ) ;
206+ coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 5000m ) ) ) ;
207+ coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_EUR" ) , new BidAsk ( 4000m ) ) ) ;
208+ coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_BTC" ) , new BidAsk ( 4500m ) ) ) ;
209+ rateProviderFactory . Providers . Add ( "coingecko" , coinAverageMock ) ;
210+
211+ var kraken = new MockRateProvider ( ) ;
212+ kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 0.1m ) ) ) ;
213+ kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_USD" ) , new BidAsk ( 0.1m ) ) ) ;
214+ kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_BTC" ) , new BidAsk ( 0.1m ) ) ) ;
215+ rateProviderFactory . Providers . Add ( "kraken" , kraken ) ;
216+ }
217+
218+ await s . RegisterNewUser ( true ) ;
219+ await s . CreateNewStore ( preferredExchange : "Kraken" ) ;
220+ await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
221+ await s . Page . Locator ( "input#PrimaryAddress" )
222+ . FillAsync (
223+ "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
224+ await s . Page . Locator ( "input#PrivateViewKey" )
225+ . FillAsync ( "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ) ;
226+ await s . Page . Locator ( "input#RestoreHeight" ) . FillAsync ( "0" ) ;
227+ await s . Page . ClickAsync ( "button[name='command'][value='set-wallet-details']" ) ;
228+ var message = await s . Page
229+ . GetByText ( "View-only wallet created. The wallet will soon become available." )
230+ . InnerTextAsync ( ) ;
231+ Assert . Contains ( "View-only wallet created" , message ) ;
232+ await s . Page . CheckAsync ( "#Enabled" ) ;
233+ await s . Page . SelectOptionAsync ( "#SettlementConfirmationThresholdChoice" , "2" ) ;
234+ await s . Page . ClickAsync ( "#SaveButton" ) ;
235+
236+ // Set rate provider
237+ await s . Page . Locator ( "#menu-item-General" ) . ClickAsync ( ) ;
238+ await s . Page . Locator ( "#menu-item-Rates" ) . ClickAsync ( ) ;
239+ await s . Page . FillAsync ( "#DefaultCurrencyPairs" , "BTC_USD,XMR_USD,XMR_BTC" ) ;
240+ await s . Page . SelectOptionAsync ( "#PrimarySource_PreferredExchange" , "kraken" ) ;
241+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
242+
243+ // Generate a new invoice
244+ await s . Page . Locator ( "a.nav-link[href*='invoices']" ) . ClickAsync ( ) ;
245+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
246+ await s . Page . FillAsync ( "#Amount" , "4.20" ) ;
247+ await s . Page . FillAsync ( "#BuyerEmail" , "monero@monero.com" ) ;
248+ await Task . Delay ( TimeSpan . FromSeconds ( 25 ) ) ; // wallet-rpc needs some time to sync. refactor this later
249+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
250+ }
201251}
0 commit comments