Skip to content

Commit e0932eb

Browse files
sondrebdangershony
andauthored
Add the ability to not auto-create hot account when activate cold sta… (#360)
* Add the ability to not auto-create hot account when activate cold staking - Need review and discussion if an additional API endpoint should be added ("setup-offline-staking") or if simply the "SetupColdStakingRequest" type should be expanded with an extra property? * Fix some failing tests Co-authored-by: dangershony <dan.gershony@gmail.com>
1 parent 308955c commit e0932eb

3 files changed

Lines changed: 40 additions & 9 deletions

File tree

src/Features/Blockcore.Features.ColdStaking/Api/Controllers/ColdStakingController.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,29 @@ public IActionResult GetColdStakingAddress([FromQuery]GetColdStakingAddressReque
176176
[Route("setup-cold-staking")]
177177
[HttpPost]
178178
public IActionResult SetupColdStaking([FromBody]SetupColdStakingRequest request)
179+
{
180+
return this.SetupColdStakingInternal(request, true);
181+
}
182+
183+
/// <summary>
184+
/// Spends funds from a normal wallet addresses to the cold staking script. It is expected that this
185+
/// spend will be detected by both the hot wallet and cold wallet and allow cold staking to occur using this
186+
/// transaction's output as input.
187+
/// </summary>
188+
/// <param name="request">A <see cref="SetupColdStakingRequest"/> object containing the cold staking setup parameters.</param>
189+
/// <returns>A <see cref="SetupColdStakingResponse"/> object containing the hex representation of the transaction.</returns>
190+
/// <seealso cref="ColdStakingManager.GetColdStakingScript(ScriptId, ScriptId)"/>
191+
[Route("setup-offline-staking")]
192+
[HttpPost]
193+
public IActionResult SetupOfflineStaking([FromBody] SetupColdStakingRequest request)
194+
{
195+
return this.SetupColdStakingInternal(request, false);
196+
}
197+
198+
private IActionResult SetupColdStakingInternal(SetupColdStakingRequest request, bool createHotAccount)
179199
{
180200
Guard.NotNull(request, nameof(request));
181-
201+
182202
// Checks the request is valid.
183203
if (!this.ModelState.IsValid)
184204
{
@@ -193,7 +213,7 @@ public IActionResult SetupColdStaking([FromBody]SetupColdStakingRequest request)
193213

194214
Transaction transaction = this.ColdStakingManager.GetColdStakingSetupTransaction(
195215
this.walletTransactionHandler, request.ColdWalletAddress, request.HotWalletAddress,
196-
request.WalletName, request.WalletAccount, request.WalletPassword, amount, feeAmount, request.SegwitChangeAddress, request.PayToScript);
216+
request.WalletName, request.WalletAccount, request.WalletPassword, amount, feeAmount, request.SegwitChangeAddress, request.PayToScript, createHotAccount);
197217

198218
var model = new SetupColdStakingResponse
199219
{

src/Features/Blockcore.Features.ColdStaking/ColdStakingManager.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,11 @@ internal HdAddress GetFirstUnusedColdStakingAddress(string walletName, bool isCo
328328
/// <param name="payToScript">Indicate script staking (P2SH or P2WSH outputs).</param>
329329
/// <returns>The <see cref="Transaction"/> for setting up cold staking.</returns>
330330
/// <exception cref="WalletException">Thrown if any of the rules listed in the remarks section of this method are broken.</exception>
331+
///
332+
331333
internal Transaction GetColdStakingSetupTransaction(IWalletTransactionHandler walletTransactionHandler,
332334
string coldWalletAddress, string hotWalletAddress, string walletName, string walletAccount,
333-
string walletPassword, Money amount, Money feeAmount, bool useSegwitChangeAddress = false, bool payToScript = false)
335+
string walletPassword, Money amount, Money feeAmount, bool useSegwitChangeAddress = false, bool payToScript = false, bool createHotAccount = true)
334336
{
335337
Guard.NotNull(walletTransactionHandler, nameof(walletTransactionHandler));
336338
Guard.NotEmpty(coldWalletAddress, nameof(coldWalletAddress));
@@ -344,7 +346,16 @@ internal Transaction GetColdStakingSetupTransaction(IWalletTransactionHandler wa
344346

345347
// Get/create the cold staking accounts.
346348
HdAccount coldAccount = this.GetOrCreateColdStakingAccount(walletName, true, walletPassword);
347-
HdAccount hotAccount = this.GetOrCreateColdStakingAccount(walletName, false, walletPassword);
349+
HdAccount hotAccount;
350+
351+
if (createHotAccount)
352+
{
353+
hotAccount = this.GetOrCreateColdStakingAccount(walletName, false, walletPassword);
354+
}
355+
else
356+
{
357+
hotAccount = this.GetColdStakingAccount(this.GetWalletByName(walletName), false);
358+
}
348359

349360
HdAddress coldAddress = coldAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == coldWalletAddress || s.Bech32Address == coldWalletAddress);
350361
HdAddress hotAddress = hotAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == hotWalletAddress || s.Bech32Address == hotWalletAddress);

src/Tests/Blockcore.Features.Wallet.Tests/WalletControllerTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ public void RecoverWalletSuccessfullyReturnsWalletModel()
330330
};
331331

332332
var mockWalletManager = new Mock<IWalletManager>();
333-
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, true)).Returns(wallet);
333+
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, null)).Returns(wallet);
334334

335335
Mock<IWalletSyncManager> walletSyncManager = new Mock<IWalletSyncManager>();
336336
walletSyncManager.Setup(w => w.WalletTip).Returns(new ChainedHeader(this.Network.GetGenesis().Header, this.Network.GetGenesis().Header.GetHash(), 3));
@@ -368,7 +368,7 @@ public void RecoverWalletWithDatedAfterCurrentSyncHeightDoesNotMoveSyncHeight()
368368
DateTime lastBlockDateTime = chainIndexer.Tip.Header.BlockTime.DateTime;
369369

370370
var mockWalletManager = new Mock<IWalletManager>();
371-
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, true)).Returns(wallet);
371+
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, null)).Returns(wallet);
372372

373373
Mock<IWalletSyncManager> walletSyncManager = new Mock<IWalletSyncManager>();
374374
walletSyncManager.Setup(w => w.WalletTip).Returns(new ChainedHeader(this.Network.GetGenesis().Header, this.Network.GetGenesis().Header.GetHash(), 3));
@@ -419,7 +419,7 @@ public void RecoverWalletWithInvalidOperationExceptionReturnsConflict()
419419
{
420420
string errorMessage = "An error occurred.";
421421
var mockWalletManager = new Mock<IWalletManager>();
422-
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, true))
422+
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, null))
423423
.Throws(new WalletException(errorMessage));
424424

425425
var controller = new WalletController(this.LoggerFactory.Object, mockWalletManager.Object, new Mock<IWalletTransactionHandler>().Object, new Mock<IWalletSyncManager>().Object, It.IsAny<ConnectionManager>(), this.Network, this.chainIndexer, new Mock<IBroadcasterManager>().Object, DateTimeProvider.Default);
@@ -445,7 +445,7 @@ public void RecoverWalletWithInvalidOperationExceptionReturnsConflict()
445445
public void RecoverWalletWithFileNotFoundExceptionReturnsNotFound()
446446
{
447447
var mockWalletManager = new Mock<IWalletManager>();
448-
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, true))
448+
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, null))
449449
.Throws(new FileNotFoundException("File not found."));
450450

451451
var controller = new WalletController(this.LoggerFactory.Object, mockWalletManager.Object, new Mock<IWalletTransactionHandler>().Object, new Mock<IWalletSyncManager>().Object, It.IsAny<ConnectionManager>(), this.Network, this.chainIndexer, new Mock<IBroadcasterManager>().Object, DateTimeProvider.Default);
@@ -472,7 +472,7 @@ public void RecoverWalletWithFileNotFoundExceptionReturnsNotFound()
472472
public void RecoverWalletWithExceptionReturnsBadRequest()
473473
{
474474
var mockWalletManager = new Mock<IWalletManager>();
475-
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, true))
475+
mockWalletManager.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null, null, null))
476476
.Throws(new FormatException("Formatting failed."));
477477

478478
var controller = new WalletController(this.LoggerFactory.Object, mockWalletManager.Object, new Mock<IWalletTransactionHandler>().Object, new Mock<IWalletSyncManager>().Object, It.IsAny<ConnectionManager>(), this.Network, this.chainIndexer, new Mock<IBroadcasterManager>().Object, DateTimeProvider.Default);

0 commit comments

Comments
 (0)