Skip to content

Commit

Permalink
allow repost of the init bond
Browse files Browse the repository at this point in the history
  • Loading branch information
chappjc committed Feb 2, 2023
1 parent f3468d8 commit 8f0e289
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
47 changes: 38 additions & 9 deletions client/core/bond.go
Expand Up @@ -159,9 +159,19 @@ func (c *Core) rotateBonds(ctx context.Context) {
coinID []byte
}

bondKeysReady := c.bondKeysReady() // nextBondKey requires login to decrypt bond xpriv
if !c.bondKeysReady() { // not logged in, and nextBondKey requires login to decrypt bond xpriv
return // nothing to do until wallets are connected on login
}

for _, dc := range c.dexConnections() {
initialized, unlocked, _ := dc.acct.status()
if !initialized {
continue // view-only or temporary connection
}
// Account unlocked is generally implied by bondKeysReady, but we will
// check per-account before post since accounts can be individually
// locked. However, we must refund bonds regardless.

lockTimeThresh := now // in case dex is down, expire (to refund when lock time is passed)
var bondExpiry int64
bondAssets := make(map[uint32]*msgjson.BondAsset)
Expand Down Expand Up @@ -204,7 +214,6 @@ func (c *Core) rotateBonds(ctx context.Context) {
}

dc.acct.authMtx.Lock()
authed := dc.acct.isAuthed // can't post bonds if we aren't logged in
tier, targetTier := dc.acct.tier, dc.acct.targetTier
bondAssetID, maxBondedAmt := dc.acct.bondAsset, dc.acct.maxBondedAmt
// Screen the unexpired bonds slices.
Expand All @@ -229,6 +238,12 @@ func (c *Core) rotateBonds(ctx context.Context) {
dc.acct.authMtx.Unlock()

for _, bond := range repost { // outside of authMtx lock
if !unlocked { // can't sign the postbond msg
c.log.Warnf("Cannot post pending bond for %v until account is unlocked.", dc.acct.host)
continue
}
// Not dependent on authed - this may be the first bond
// (registering) where bondConfirmed does authDEX if needed.
if bondAsset, ok := bondAssets[bond.AssetID]; ok {
c.monitorBondConfs(dc, bond, bondAsset.Confs)
} else {
Expand Down Expand Up @@ -336,10 +351,10 @@ func (c *Core) rotateBonds(ctx context.Context) {
expiredStrength := sumBondStrengths(dc.acct.expiredBonds)
dc.acct.authMtx.Unlock()

if authed && mustPost > 0 && targetTier > 0 && bondExpiry > 0 {
if mustPost > 0 && targetTier > 0 && bondExpiry > 0 {
c.log.Infof("Gotta post %d bond increments now. Target tier %d, current tier %d (%d weak, %d pending)",
mustPost, targetTier, tier, weakStrength, pendingStrength)
if !bondKeysReady || dc.status() != comms.Connected {
if !unlocked || dc.status() != comms.Connected {
c.log.Warnf("Unable to post the required bond while disconnected or logged out.")
continue
}
Expand Down Expand Up @@ -722,6 +737,12 @@ func (c *Core) PostBond(form *PostBondForm) (*PostBondResult, error) {
return nil, fmt.Errorf("app not initialized")
}

// Check that the bond amount is non-zero before we touch wallets and make
// connections to the DEX host.
if form.Bond == 0 {
return nil, newError(bondAmtErr, "zero registration fees not allowed")
}

// Get the wallet to author the transaction. Default to DCR.
bondAssetID := uint32(42)
if form.Asset != nil {
Expand All @@ -732,10 +753,13 @@ func (c *Core) PostBond(form *PostBondForm) (*PostBondResult, error) {
if err != nil {
return nil, fmt.Errorf("cannot connect to %s wallet to pay fee: %w", bondAssetSymbol, err)
}

if _, ok := wallet.Wallet.(asset.Bonder); !ok { // will fail in MakeBondTx, but assert early
return nil, fmt.Errorf("wallet %v is not an asset.Bonder", bondAssetSymbol)
}
_, err = wallet.refreshUnlock()
if err != nil {
return nil, fmt.Errorf("bond asset wallet %v is locked", unbip(bondAssetID))
}

// Check the app password.
crypter, err := c.encryptionKey(form.AppPass)
Expand Down Expand Up @@ -771,6 +795,14 @@ func (c *Core) PostBond(form *PostBondForm) (*PostBondResult, error) {
"(use UpdateBondOptions to change bond maintenance settings)")
}
} else {
// Before connecting to the DEX host, do a quick balance check to ensure
// we at least have the nominal bond amount available.
if bal, err := wallet.Balance(); err != nil {
return nil, newError(bondAssetErr, "unable to check wallet balance: %w", err)
} else if bal.Available < form.Bond {
return nil, newError(bondAssetErr, "insufficient available balance")
}

maxBondedAmt := 4 * form.Bond // default
if form.MaxBondedAmt != nil {
maxBondedAmt = *form.MaxBondedAmt
Expand Down Expand Up @@ -841,10 +873,6 @@ func (c *Core) PostBond(form *PostBondForm) (*PostBondResult, error) {
return nil, newError(bondTimeErr, "lock time of %d in the past", form.LockTime)
}

// Check that the bond amount is non-zero.
if form.Bond == 0 {
return nil, newError(bondAmtErr, "zero registration fees not allowed")
}
// Check that the bond amount matches the caller's expectations.
if form.Bond < bondAsset.Amt {
return nil, newError(bondAmtErr, "specified bond amount is less than the DEX-provided amount. %d < %d",
Expand Down Expand Up @@ -956,6 +984,7 @@ func (c *Core) makeAndPostBond(dc *dexConnection, acctExists bool, wallet *xcWal
c.connMtx.Lock()
c.conns[dc.acct.host] = dc
c.connMtx.Unlock()
// NOTE: it's still not authed if this was the first bond
}

// Broadcast the bond and start waiting for confs.
Expand Down
9 changes: 8 additions & 1 deletion client/core/types.go
Expand Up @@ -841,7 +841,14 @@ func (a *dexAccount) lock() {
a.keyMtx.Unlock()
}

// locked will be true if the account private key is currently decrypted.
func (a *dexAccount) status() (initialized, unlocked, authed bool) {
a.keyMtx.RLock()
defer a.keyMtx.RUnlock()
return len(a.encKey) > 0, a.privKey != nil, a.isAuthed
}

// locked will be true if the account private key is currently decrypted, or
// there are no account keys generated yet.
func (a *dexAccount) locked() bool {
a.keyMtx.RLock()
defer a.keyMtx.RUnlock()
Expand Down

0 comments on commit 8f0e289

Please sign in to comment.