Skip to content

Commit

Permalink
Merge pull request #5303 from filecoin-project/feat/wallet-market-info
Browse files Browse the repository at this point in the history
Better CLI for wallet market withdraw and client info
  • Loading branch information
magik6k authored Jan 8, 2021
2 parents afb9e5f + c58086e commit 32dcfb4
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 21 deletions.
2 changes: 2 additions & 0 deletions api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,8 @@ type FullNode interface {

// MarketAddBalance adds funds to the market actor
MarketAddBalance(ctx context.Context, wallet, addr address.Address, amt types.BigInt) (cid.Cid, error)
// MarketGetReserved gets the amount of funds that are currently reserved for the address
MarketGetReserved(ctx context.Context, addr address.Address) (types.BigInt, error)
// MarketReserveFunds reserves funds for a deal
MarketReserveFunds(ctx context.Context, wallet address.Address, addr address.Address, amt types.BigInt) (cid.Cid, error)
// MarketReleaseFunds releases funds reserved by MarketReserveFunds
Expand Down
7 changes: 6 additions & 1 deletion api/apistruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,11 @@ type FullNodeStruct struct {
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
MsigRemoveSigner func(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) `perm:"sign"`

MarketAddBalance func(ctx context.Context, wallet, addr address.Address, amt types.BigInt) (cid.Cid, error) `perm:"sign"`
MarketGetReserved func(ctx context.Context, addr address.Address) (types.BigInt, error) `perm:"sign"`
MarketReserveFunds func(ctx context.Context, wallet address.Address, addr address.Address, amt types.BigInt) (cid.Cid, error) `perm:"sign"`
MarketReleaseFunds func(ctx context.Context, addr address.Address, amt types.BigInt) error `perm:"sign"`
MarketWithdraw func(ctx context.Context, wallet, addr address.Address, amt types.BigInt) (cid.Cid, error) `perm:"sign"`
MarketAddBalance func(ctx context.Context, wallet, addr address.Address, amt types.BigInt) (cid.Cid, error) `perm:"sign"`

PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
Expand Down Expand Up @@ -1153,6 +1154,10 @@ func (c *FullNodeStruct) MarketAddBalance(ctx context.Context, wallet address.Ad
return c.Internal.MarketAddBalance(ctx, wallet, addr, amt)
}

func (c *FullNodeStruct) MarketGetReserved(ctx context.Context, addr address.Address) (types.BigInt, error) {
return c.Internal.MarketGetReserved(ctx, addr)
}

func (c *FullNodeStruct) MarketReserveFunds(ctx context.Context, wallet address.Address, addr address.Address, amt types.BigInt) (cid.Cid, error) {
return c.Internal.MarketReserveFunds(ctx, wallet, addr, amt)
}
Expand Down
14 changes: 13 additions & 1 deletion chain/market/fundmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ func (fm *FundManager) Withdraw(ctx context.Context, wallet, addr address.Addres
return fm.getFundedAddress(addr).withdraw(ctx, wallet, amt)
}

// GetReserved returns the amount that is currently reserved for the address
func (fm *FundManager) GetReserved(addr address.Address) abi.TokenAmount {
return fm.getFundedAddress(addr).getReserved()
}

// FundedAddressState keeps track of the state of an address with funds in the
// datastore
type FundedAddressState struct {
Expand All @@ -148,7 +153,7 @@ type fundedAddress struct {
env *fundManagerEnvironment
str *Store

lk sync.Mutex
lk sync.RWMutex
state *FundedAddressState

// Note: These request queues are ephemeral, they are not saved to store
Expand Down Expand Up @@ -184,6 +189,13 @@ func (a *fundedAddress) start() {
}
}

func (a *fundedAddress) getReserved() abi.TokenAmount {
a.lk.RLock()
defer a.lk.RUnlock()

return a.state.AmtReserved
}

func (a *fundedAddress) reserve(ctx context.Context, wallet address.Address, amt abi.TokenAmount) (cid.Cid, error) {
return a.requestAndWait(ctx, wallet, amt, &a.reservations)
}
Expand Down
18 changes: 15 additions & 3 deletions cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1770,10 +1770,22 @@ var clientBalancesCmd = &cli.Command{
return err
}

fmt.Printf("Client Market Info:\n")
reserved, err := api.MarketGetReserved(ctx, addr)
if err != nil {
return err
}

avail := big.Sub(big.Sub(balance.Escrow, balance.Locked), reserved)
if avail.LessThan(big.Zero()) {
avail = big.Zero()
}

fmt.Printf("Client Market Balance for address %s:\n", addr)

fmt.Printf("Locked Funds:\t%s\n", types.FIL(balance.Locked))
fmt.Printf("Escrowed Funds:\t%s\n", types.FIL(balance.Escrow))
fmt.Printf(" Escrowed Funds: %s\n", types.FIL(balance.Escrow))
fmt.Printf(" Locked Funds: %s\n", types.FIL(balance.Locked))
fmt.Printf(" Reserved Funds: %s\n", types.FIL(reserved))
fmt.Printf(" Available to Withdraw: %s\n", types.FIL(avail))

return nil
},
Expand Down
55 changes: 39 additions & 16 deletions cli/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,13 +519,13 @@ var walletMarketWithdraw = &cli.Command{
ArgsUsage: "[amount (FIL) optional, otherwise will withdraw max available]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "Specify address to withdraw funds from, otherwise it will use the default wallet address",
Aliases: []string{"f"},
Name: "wallet",
Usage: "Specify address to withdraw funds to, otherwise it will use the default wallet address",
Aliases: []string{"w"},
},
&cli.StringFlag{
Name: "address",
Usage: "Market address to withdraw from (account or miner actor address, defaults to --from address)",
Usage: "Market address to withdraw from (account or miner actor address, defaults to --wallet address)",
Aliases: []string{"a"},
},
},
Expand All @@ -537,35 +537,55 @@ var walletMarketWithdraw = &cli.Command{
defer closer()
ctx := ReqContext(cctx)

var from address.Address
if cctx.String("from") != "" {
from, err = address.NewFromString(cctx.String("from"))
var wallet address.Address
if cctx.String("wallet") != "" {
wallet, err = address.NewFromString(cctx.String("wallet"))
if err != nil {
return xerrors.Errorf("parsing from address: %w", err)
}
} else {
from, err = api.WalletDefaultAddress(ctx)
wallet, err = api.WalletDefaultAddress(ctx)
if err != nil {
return xerrors.Errorf("getting default wallet address: %w", err)
}
}

addr := from
addr := wallet
if cctx.String("address") != "" {
addr, err = address.NewFromString(cctx.String("address"))
if err != nil {
return xerrors.Errorf("parsing market address: %w", err)
}
}

// Work out if there are enough unreserved, unlocked funds to withdraw
bal, err := api.StateMarketBalance(ctx, addr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting market balance for address %s: %w", addr.String(), err)
}

avail := big.Subtract(bal.Escrow, bal.Locked)
reserved, err := api.MarketGetReserved(ctx, addr)
if err != nil {
return xerrors.Errorf("getting market reserved amount for address %s: %w", addr.String(), err)
}

avail := big.Subtract(big.Subtract(bal.Escrow, bal.Locked), reserved)

notEnoughErr := func(msg string) error {
return xerrors.Errorf("%s; "+
"available (%s) = escrow (%s) - locked (%s) - reserved (%s)",
msg, types.FIL(avail), types.FIL(bal.Escrow), types.FIL(bal.Locked), types.FIL(reserved))
}

if avail.IsZero() || avail.LessThan(big.Zero()) {
avail = big.Zero()
return notEnoughErr("no funds available to withdraw")
}

// Default to withdrawing all available funds
amt := avail

// If there was an amount argument, only withdraw that amount
if cctx.Args().Present() {
f, err := types.ParseFIL(cctx.Args().First())
if err != nil {
Expand All @@ -575,16 +595,19 @@ var walletMarketWithdraw = &cli.Command{
amt = abi.TokenAmount(f)
}

if amt.GreaterThan(avail) {
return xerrors.Errorf("can't withdraw more funds than available; requested: %s; available: %s", types.FIL(amt), types.FIL(avail))
// Check the amount is positive
if amt.IsZero() || amt.LessThan(big.Zero()) {
return xerrors.Errorf("amount must be > 0")
}

if avail.IsZero() {
return xerrors.Errorf("zero unlocked funds available to withdraw")
// Check there are enough available funds
if amt.GreaterThan(avail) {
msg := fmt.Sprintf("can't withdraw more funds than available; requested: %s", types.FIL(amt))
return notEnoughErr(msg)
}

fmt.Printf("Submitting WithdrawBalance message for amount %s for address %s\n", types.FIL(amt), from.String())
smsg, err := api.MarketWithdraw(ctx, from, addr, amt)
fmt.Printf("Submitting WithdrawBalance message for amount %s for address %s\n", types.FIL(amt), wallet.String())
smsg, err := api.MarketWithdraw(ctx, wallet, addr, amt)
if err != nil {
return xerrors.Errorf("fund manager withdraw error: %w", err)
}
Expand Down
16 changes: 16 additions & 0 deletions documentation/en/api-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
* [LogSetLevel](#LogSetLevel)
* [Market](#Market)
* [MarketAddBalance](#MarketAddBalance)
* [MarketGetReserved](#MarketGetReserved)
* [MarketReleaseFunds](#MarketReleaseFunds)
* [MarketReserveFunds](#MarketReserveFunds)
* [MarketWithdraw](#MarketWithdraw)
Expand Down Expand Up @@ -1676,6 +1677,21 @@ Response:
}
```

### MarketGetReserved
MarketGetReserved gets the amount of funds that are currently reserved for the address


Perms: sign

Inputs:
```json
[
"f01234"
]
```

Response: `"0"`

### MarketReleaseFunds
MarketReleaseFunds releases funds reserved by MarketReserveFunds

Expand Down
4 changes: 4 additions & 0 deletions node/impl/market/market.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func (a *MarketAPI) MarketAddBalance(ctx context.Context, wallet, addr address.A
return smsg.Cid(), nil
}

func (a *MarketAPI) MarketGetReserved(ctx context.Context, addr address.Address) (types.BigInt, error) {
return a.FMgr.GetReserved(addr), nil
}

func (a *MarketAPI) MarketReserveFunds(ctx context.Context, wallet address.Address, addr address.Address, amt types.BigInt) (cid.Cid, error) {
return a.FMgr.Reserve(ctx, wallet, addr, amt)
}
Expand Down

0 comments on commit 32dcfb4

Please sign in to comment.