Merge pull request #5303 from filecoin-project/feat/wallet-market-info
Better CLI for wallet market withdraw and client info
This commit is contained in:
commit
32dcfb4842
@ -517,6 +517,8 @@ type FullNode interface {
|
|||||||
|
|
||||||
// MarketAddBalance adds funds to the market actor
|
// MarketAddBalance adds funds to the market actor
|
||||||
MarketAddBalance(ctx context.Context, wallet, addr address.Address, amt types.BigInt) (cid.Cid, error)
|
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 reserves funds for a deal
|
||||||
MarketReserveFunds(ctx context.Context, wallet address.Address, addr address.Address, amt types.BigInt) (cid.Cid, error)
|
MarketReserveFunds(ctx context.Context, wallet address.Address, addr address.Address, amt types.BigInt) (cid.Cid, error)
|
||||||
// MarketReleaseFunds releases funds reserved by MarketReserveFunds
|
// MarketReleaseFunds releases funds reserved by MarketReserveFunds
|
||||||
|
@ -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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
|
||||||
@ -1153,6 +1154,10 @@ func (c *FullNodeStruct) MarketAddBalance(ctx context.Context, wallet address.Ad
|
|||||||
return c.Internal.MarketAddBalance(ctx, wallet, addr, amt)
|
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) {
|
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)
|
return c.Internal.MarketReserveFunds(ctx, wallet, addr, amt)
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,11 @@ func (fm *FundManager) Withdraw(ctx context.Context, wallet, addr address.Addres
|
|||||||
return fm.getFundedAddress(addr).withdraw(ctx, wallet, amt)
|
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
|
// FundedAddressState keeps track of the state of an address with funds in the
|
||||||
// datastore
|
// datastore
|
||||||
type FundedAddressState struct {
|
type FundedAddressState struct {
|
||||||
@ -148,7 +153,7 @@ type fundedAddress struct {
|
|||||||
env *fundManagerEnvironment
|
env *fundManagerEnvironment
|
||||||
str *Store
|
str *Store
|
||||||
|
|
||||||
lk sync.Mutex
|
lk sync.RWMutex
|
||||||
state *FundedAddressState
|
state *FundedAddressState
|
||||||
|
|
||||||
// Note: These request queues are ephemeral, they are not saved to store
|
// Note: These request queues are ephemeral, they are not saved to store
|
||||||
@ -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) {
|
func (a *fundedAddress) reserve(ctx context.Context, wallet address.Address, amt abi.TokenAmount) (cid.Cid, error) {
|
||||||
return a.requestAndWait(ctx, wallet, amt, &a.reservations)
|
return a.requestAndWait(ctx, wallet, amt, &a.reservations)
|
||||||
}
|
}
|
||||||
|
@ -1770,10 +1770,22 @@ var clientBalancesCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Client Market Info:\n")
|
reserved, err := api.MarketGetReserved(ctx, addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("Locked Funds:\t%s\n", types.FIL(balance.Locked))
|
avail := big.Sub(big.Sub(balance.Escrow, balance.Locked), reserved)
|
||||||
fmt.Printf("Escrowed Funds:\t%s\n", types.FIL(balance.Escrow))
|
if avail.LessThan(big.Zero()) {
|
||||||
|
avail = big.Zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Client Market Balance for address %s:\n", addr)
|
||||||
|
|
||||||
|
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
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -519,13 +519,13 @@ var walletMarketWithdraw = &cli.Command{
|
|||||||
ArgsUsage: "[amount (FIL) optional, otherwise will withdraw max available]",
|
ArgsUsage: "[amount (FIL) optional, otherwise will withdraw max available]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "from",
|
Name: "wallet",
|
||||||
Usage: "Specify address to withdraw funds from, otherwise it will use the default wallet address",
|
Usage: "Specify address to withdraw funds to, otherwise it will use the default wallet address",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"w"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "address",
|
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"},
|
Aliases: []string{"a"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -537,20 +537,20 @@ var walletMarketWithdraw = &cli.Command{
|
|||||||
defer closer()
|
defer closer()
|
||||||
ctx := ReqContext(cctx)
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
var from address.Address
|
var wallet address.Address
|
||||||
if cctx.String("from") != "" {
|
if cctx.String("wallet") != "" {
|
||||||
from, err = address.NewFromString(cctx.String("from"))
|
wallet, err = address.NewFromString(cctx.String("wallet"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("parsing from address: %w", err)
|
return xerrors.Errorf("parsing from address: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
from, err = api.WalletDefaultAddress(ctx)
|
wallet, err = api.WalletDefaultAddress(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting default wallet address: %w", err)
|
return xerrors.Errorf("getting default wallet address: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := from
|
addr := wallet
|
||||||
if cctx.String("address") != "" {
|
if cctx.String("address") != "" {
|
||||||
addr, err = address.NewFromString(cctx.String("address"))
|
addr, err = address.NewFromString(cctx.String("address"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -558,14 +558,34 @@ var walletMarketWithdraw = &cli.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Work out if there are enough unreserved, unlocked funds to withdraw
|
||||||
bal, err := api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
bal, err := api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting market balance for address %s: %w", addr.String(), err)
|
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
|
amt := avail
|
||||||
|
|
||||||
|
// If there was an amount argument, only withdraw that amount
|
||||||
if cctx.Args().Present() {
|
if cctx.Args().Present() {
|
||||||
f, err := types.ParseFIL(cctx.Args().First())
|
f, err := types.ParseFIL(cctx.Args().First())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -575,16 +595,19 @@ var walletMarketWithdraw = &cli.Command{
|
|||||||
amt = abi.TokenAmount(f)
|
amt = abi.TokenAmount(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the amount is positive
|
||||||
|
if amt.IsZero() || amt.LessThan(big.Zero()) {
|
||||||
|
return xerrors.Errorf("amount must be > 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check there are enough available funds
|
||||||
if amt.GreaterThan(avail) {
|
if amt.GreaterThan(avail) {
|
||||||
return xerrors.Errorf("can't withdraw more funds than available; requested: %s; available: %s", types.FIL(amt), types.FIL(avail))
|
msg := fmt.Sprintf("can't withdraw more funds than available; requested: %s", types.FIL(amt))
|
||||||
|
return notEnoughErr(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if avail.IsZero() {
|
fmt.Printf("Submitting WithdrawBalance message for amount %s for address %s\n", types.FIL(amt), wallet.String())
|
||||||
return xerrors.Errorf("zero unlocked funds available to withdraw")
|
smsg, err := api.MarketWithdraw(ctx, wallet, addr, amt)
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("fund manager withdraw error: %w", err)
|
return xerrors.Errorf("fund manager withdraw error: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
* [LogSetLevel](#LogSetLevel)
|
* [LogSetLevel](#LogSetLevel)
|
||||||
* [Market](#Market)
|
* [Market](#Market)
|
||||||
* [MarketAddBalance](#MarketAddBalance)
|
* [MarketAddBalance](#MarketAddBalance)
|
||||||
|
* [MarketGetReserved](#MarketGetReserved)
|
||||||
* [MarketReleaseFunds](#MarketReleaseFunds)
|
* [MarketReleaseFunds](#MarketReleaseFunds)
|
||||||
* [MarketReserveFunds](#MarketReserveFunds)
|
* [MarketReserveFunds](#MarketReserveFunds)
|
||||||
* [MarketWithdraw](#MarketWithdraw)
|
* [MarketWithdraw](#MarketWithdraw)
|
||||||
@ -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
|
||||||
MarketReleaseFunds releases funds reserved by MarketReserveFunds
|
MarketReleaseFunds releases funds reserved by MarketReserveFunds
|
||||||
|
|
||||||
|
@ -42,6 +42,10 @@ func (a *MarketAPI) MarketAddBalance(ctx context.Context, wallet, addr address.A
|
|||||||
return smsg.Cid(), nil
|
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) {
|
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)
|
return a.FMgr.Reserve(ctx, wallet, addr, amt)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user