# `DpExchange.Core.Types.Withdrawal`
[🔗](https://github.com/DistortionPoint/dp-exchange-core/blob/v0.3.120/lib/dp_exchange/core/types/withdrawal.ex#L1)

A withdrawal of an asset to an external address.

**This is the only operation in the contract that cannot be undone.** An order can be
cancelled, a position closed, a stake redeemed. A withdrawal that leaves the venue is gone,
and every field here is shaped by that.

## The fee is quoted separately and may not be the fee charged

Venues expose a fee estimate as its own call. The estimate and the charge can differ —
network conditions move between the two — so `:fee` is what the venue **charged** where it
has said, and `nil` where it has not yet. An estimate does not belong in this field: a
caller reconciling against an estimate as though it were the charge will be short by the
difference, every time, in the same direction.

## `:amount` is what was requested, not necessarily what arrives

Where a venue deducts the fee from the amount rather than in addition to it, the recipient
receives less than `:amount`. Venues differ, and this layer does not reinterpret. A caller
that must know what lands asks the venue, or reads `:fee` and its own venue's convention —
it does not assume.

## `:status` never means "arrived"

The venue can say it broadcast a transaction. It cannot say the recipient has it, and no
status here should be read as confirmation of receipt:

  * `:requested` — accepted by the venue, nothing on chain
  * `:pending` — being processed, possibly awaiting a manual review
  * `:broadcast` — a transaction exists; `:tx_id` is set
  * `:completed` — the venue considers it done
  * `:cancelled` / `:failed` — it did not happen

`:completed` is the venue's opinion, and it is the strongest claim available here.

# `status`

```elixir
@type status() ::
  :requested | :pending | :broadcast | :completed | :cancelled | :failed
```

# `t`

```elixir
@type t() :: %DpExchange.Core.Types.Withdrawal{
  address: String.t() | nil,
  amount: Decimal.t(),
  asset: String.t(),
  fee: Decimal.t() | nil,
  id: String.t(),
  memo: String.t() | nil,
  network: String.t() | nil,
  provider: atom(),
  requested_at: DateTime.t() | nil,
  status: status(),
  tx_id: String.t() | nil
}
```

# `new`

```elixir
@spec new(keyword() | map()) :: t()
```

Builds a `t:t/0`, failing closed if a required field is absent or `nil`.

`@enforce_keys` guards presence, not `nil` — see `DpExchange.Core.Types.Validate`.

Also raises on an `:amount` of zero or less, a negative `:fee`, a `:status` outside the six
above (a venue's own word is the venue's news to map, never the nearest atom), and a
`:broadcast` withdrawal with no `:tx_id`: a withdrawal that claims a transaction it cannot
name has already moved money.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
