Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
use Butschster\Kraken\Responses\{AccountBalanceResponse,
AddOrderResponse,
AssetInfoResponse,
BoolStatusResponse,
CancelOrderResponse,
CancelOrdersAfterTimeoutResponse,
ClosedOrdersResponse,
DepositAddressesResponse,
DepositMethodsResponse,
EarnAllocationsResponse,
EarnStrategiesResponse,
Entities\AddOrder\OrderAdded,
Entities\CancelOrdersAfterTimeout,
Entities\DepositMethods,
Entities\Earn\Allocation\Allocations,
Entities\Earn\EarnStrategies,
Entities\Orders\ClosedOrders,
Entities\ServerTime,
Entities\SystemStatus,
Expand All @@ -38,6 +43,7 @@
use Butschster\Kraken\ValueObjects\{
AssetClass, AssetPair, TradableInfo
};
use Butschster\Kraken\Requests\EarnAllocationRequest;
use DateTimeInterface;
use Illuminate\Support\Str;
use JMS\Serializer\SerializerInterface;
Expand Down Expand Up @@ -307,6 +313,56 @@ public function getWithdrawalInformation(string $asset, string $key, BigDecimal
)->result;
}

public function getEarnStrategies(?string $asset = null, array $lockType = ['flex', 'bonded', 'instant'], bool $ascending = false): EarnStrategies
{
return $this->request(
method: 'private/Earn/Strategies',
responsePayload: EarnStrategiesResponse::class,
parameters: [
'asset' => $asset,
'lock_type' => $lockType,
'ascending' => $ascending ? 'true' : 'false',
// 'cursor' => '10', // not yet implemented
// 'limit' => 10, // not yet implemented
],
)->result;
}

public function getEarnAllocations(string $convertedAsset = 'USD', bool $hideZeroAllocations = false, bool $ascending = false): Allocations
{
return $this->request(
method: 'private/Earn/Allocations',
responsePayload: EarnAllocationsResponse::class,
parameters: [
'ascending' => $ascending ? 'true' : 'false',
'converted_asset' => $convertedAsset,
'hide_zero_allocations' => $hideZeroAllocations ? 'true' : 'false',
]
)->result;
}

public function allocateEarnFunds(BigDecimal $amount, string $strategyId): bool
{
$request = new EarnAllocationRequest($amount, $strategyId);

return $this->request(
method: 'private/Earn/Allocate',
responsePayload: BoolStatusResponse::class,
parameters: $request->toArray(),
)->result;
}

public function deallocateEarnFunds(BigDecimal $amount, string $strategyId): bool
{
$request = new EarnAllocationRequest($amount, $strategyId);

return $this->request(
method: 'private/Earn/Deallocate',
responsePayload: BoolStatusResponse::class,
parameters: $request->toArray(),
)->result;
}

/**
* Make request
*
Expand Down Expand Up @@ -350,7 +406,7 @@ public function request(


$responseObject = $this->serializer->deserialize(
$response->getBody()->getContents(),
(string) $response->getBody(),
$responsePayload,
'json',
);
Expand Down
122 changes: 122 additions & 0 deletions src/Contracts/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Butschster\Kraken\Responses\Entities\CancelOrdersAfterTimeout;
use Butschster\Kraken\Responses\Entities\DepositAddresses;
use Butschster\Kraken\Responses\Entities\DepositMethods;
use Butschster\Kraken\Responses\Entities\Earn\Allocation\Allocations;
use Butschster\Kraken\Responses\Entities\Earn\EarnStrategies;
use Butschster\Kraken\Responses\Entities\OrderBook\Orders;
use Butschster\Kraken\Responses\Entities\Orders\ClosedOrders;
use Butschster\Kraken\Responses\Entities\Orders\Order;
Expand All @@ -23,6 +25,7 @@
use Butschster\Kraken\ValueObjects\AssetPair;
use Butschster\Kraken\ValueObjects\TradableInfo;
use DateTimeInterface;
use GuzzleHttp\Exception\GuzzleException;

interface Client
{
Expand Down Expand Up @@ -208,4 +211,123 @@ public function getDepositAddresses(string $asset, string $method, bool $new = f
* @return WithdrawalInformation
*/
public function getWithdrawalInformation(string $asset, string $key, BigDecimal $amount): WithdrawalInformation;

/**
* List earn strategies along with their parameters.
*
* Requires a valid API key but not specific permission is required.
*
* Returns only strategies that are available to the user based on geographic region.
*
* When the user does not meet the tier restriction:
* - `can_allocate` will be false
* - `allocation_restriction_info` indicates `Tier` as the restriction reason
*
* Earn products generally require Intermediate tier. Get your account verified to access earn.
*
* A note about `lock_type`:
* - `instant`: can be deallocated without an unbonding period. This is called flexible in the UI.
* - `bonded`: has an unbonding period. Deallocation will not happen until this period has passed.
* - `flex`: "Kraken rewards". This is earning on your spot balances where eligible. It's turned on account wide from the UI and you cannot manually allocate to these strategies.
*
* Paging isn't yet implemented, so the endpoint always returns all data in the first page.
*
* @see https://docs.kraken.com/api/docs/rest-api/list-strategies
* @param string|null $asset
* @param array $lockType
* @param bool $ascending
* @return EarnStrategies
*/
public function getEarnStrategies(?string $asset = null, array $lockType = ['flex', 'bonded', 'instant'], bool $ascending = false): EarnStrategies;

/**
* List all allocations for the user.
*
* Requires the `Query Funds` API key permission.
*
* By default, all allocations are returned, even for strategies that have been used in the past and have zero balance now.
* This allows the user to see how much was earned with a given strategy in the past. The `hide_zero_allocations` parameter
* can be used to remove zero balance entries from the output. Paging hasn't been implemented for this method as we don't
* expect the result for a particular user to be overwhelmingly large.
*
* All amounts in the output can be denominated in a currency of the user's choice (the `converted_asset` parameter).
*
* Information about when the next reward will be paid to the client is also provided in the output.
*
* Allocated funds can be in up to 4 states:
* - bonding
* - allocated
* - exit_queue (ETH only)
* - unbonding
*
* Any funds in `total` not in `bonding`/`unbonding` are simply allocated and earning rewards. Depending on the strategy, funds
* in the other 3 states can also be earning rewards. Consult the output of `/Earn/Strategies` to know whether `bonding`/`unbonding`
* earn rewards. `ETH` in `exit_queue` still earns rewards.
*
* Note that for `ETH`, when the funds are in the `exit_queue` state, the `expires` time given is the time when the funds will have
* finished unbonding, not when they go from exit queue to unbonding.
*
* (Un)bonding time estimate can be inaccurate right after having (de)allocated the funds. Wait 1-2 minutes after (de)allocating
* to get an accurate result.
*
* @see https://docs.kraken.com/api/docs/rest-api/list-allocations
* @param string $convertedAsset The currency to which amounts should be converted. Default is 'USD'.
* @param bool $hideZeroAllocations Whether to hide allocations with zero balance. Default is false.
* @param bool $ascending Whether to sort the results in ascending order. Default is false.
* @return Allocations The list of allocations.
*/
public function getEarnAllocations(string $convertedAsset = 'USD', bool $hideZeroAllocations = false, bool $ascending = false): Allocations;

/**
* Allocate funds to the Strategy.
*
* Requires the `Earn Funds` API key permission. The amount must always be defined.
*
* This method is asynchronous. A couple of preflight checks are performed synchronously on behalf of the
* method before it is dispatched further. The client is required to poll the result using the
* `/0/private/Earn/AllocateStatus` endpoint.
*
* There can be only one (de)allocation request in progress for a given user and strategy at any time. While the operation is in progress:
* - `pending` attribute in `/Earn/Allocations` response for the strategy indicates that funds are being allocated,
* - `pending` attribute in `/Earn/AllocateStatus` response will be true.
*
* Following specific errors within `Earnings` class can be returned by this method:
* - Minimum allocation: `EEarnings:Below min:(De)allocation operation amount less than minimum`
* - Allocation in progress: `EEarnings:Busy:Another (de)allocation for the same strategy is in progress`
* - Service temporarily unavailable: `EEarnings:Busy`. Try again in a few minutes.
* - User tier verification: `EEarnings:Permission denied:The user's tier is not high enough`
* - Strategy not found: `EGeneral:Invalid arguments:Invalid strategy ID`
*
* @see https://docs.kraken.com/api/docs/rest-api/allocate-strategy
* @param BigDecimal $amount
* @param string $strategyId
* @return bool
*/
public function allocateEarnFunds(BigDecimal $amount, string $strategyId): bool;


/**
* Deallocate funds from a strategy.
*
* Requires the `Earn Funds` API key permission. The amount must always be defined.
*
* This method is asynchronous. A couple of preflight checks are performed synchronously on behalf of the
* method before it is dispatched further. If the method returns HTTP 202 code, the client is required to poll
* the result using the `/Earn/DeallocateStatus` endpoint.
*
* There can be only one (de)allocation request in progress for a given user and strategy. While the operation is in progress:
* - `pending` attribute in `Allocations` response for the strategy will hold the amount that is being deallocated (negative amount)
* - `pending` attribute in `DeallocateStatus` response will be true.
*
* Following specific errors within `Earnings` class can be returned by this method:
* - Minimum allocation: `EEarnings:Below min:(De)allocation operation amount less than minimum allowed`
* - Allocation in progress: `EEarnings:Busy:Another (de)allocation for the same strategy is in progress`
* - Strategy not found: `EGeneral:Invalid arguments:Invalid strategy ID`
*
* @see https://docs.kraken.com/api/docs/rest-api/deallocate-strategy
* @param BigDecimal $amount
* @param string $strategyId
* @return bool
*/
public function deallocateEarnFunds(BigDecimal $amount, string $strategyId): bool;
}
19 changes: 19 additions & 0 deletions src/Contracts/EarnAllocationRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Butschster\Kraken\Contracts;

use Brick\Math\BigDecimal;
use Illuminate\Contracts\Support\Arrayable;

interface EarnAllocationRequest extends Arrayable
{
/**
* The amount to allocate.
*/
public function amount(): ?BigDecimal;

/**
* A unique identifier of the chosen earn strategy, as returned from `/0/private/Earn/Strategies`.
*/
public function strategy_id(): string;
}
43 changes: 43 additions & 0 deletions src/Requests/EarnAllocationRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Butschster\Kraken\Requests;

use Brick\Math\BigDecimal;

class EarnAllocationRequest implements \Butschster\Kraken\Contracts\EarnAllocationRequest
{
public function __construct(
private ?BigDecimal $amount = null, private ?string $strategy_id = null) {}

public function setAmount(?BigDecimal $amount): self
{
$this->amount = $amount;

return $this;
}

public function setStrategyId(?string $strategy_id): self
{
$this->strategy_id = $strategy_id;

return $this;
}

public function amount(): ?BigDecimal
{
return $this->amount;
}

public function strategy_id(): string
{
return $this->strategy_id;
}

public function toArray(): array
{
return [
'amount' => (string) $this->amount(),
'strategy_id' => $this->strategy_id(),
];
}
}
11 changes: 11 additions & 0 deletions src/Responses/BoolStatusResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Butschster\Kraken\Responses;

use JMS\Serializer\Annotation\Type;

class BoolStatusResponse extends AbstractResponse
{
#[Type('bool')]
public bool $result;
}
12 changes: 12 additions & 0 deletions src/Responses/EarnAllocationsResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Butschster\Kraken\Responses;

use Butschster\Kraken\Responses\Entities\Earn\Allocation\Allocations;
use JMS\Serializer\Annotation\Type;

class EarnAllocationsResponse extends AbstractResponse
{
#[Type("Butschster\Kraken\Responses\Entities\Earn\Allocation\Allocations")]
public ?Allocations $result = null;
}
13 changes: 13 additions & 0 deletions src/Responses/EarnStrategiesResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Butschster\Kraken\Responses;

use Butschster\Kraken\Responses\AbstractResponse;
use Butschster\Kraken\Responses\Entities\Earn\EarnStrategies;
use JMS\Serializer\Annotation\Type;

class EarnStrategiesResponse extends AbstractResponse
{
#[Type("Butschster\Kraken\Responses\Entities\Earn\EarnStrategies")]
public ?EarnStrategies $result = null;
}
23 changes: 23 additions & 0 deletions src/Responses/Entities/Earn/Allocation/Allocation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Butschster\Kraken\Responses\Entities\Earn\Allocation;

use JMS\Serializer\Annotation\Type;

class Allocation
{
#[Type('string')]
public string $strategy_id;

#[Type('string')]
public string $native_asset;

#[Type("Butschster\Kraken\Responses\Entities\Earn\Allocation\AmountAllocated")]
public AmountAllocated $amount_allocated;

#[Type("Butschster\Kraken\Responses\Entities\Earn\Allocation\TotalRewarded")]
public TotalRewarded $total_rewarded;

#[Type("Butschster\Kraken\Responses\Entities\Earn\Allocation\Payout")]
public Payout $payout;
}
24 changes: 24 additions & 0 deletions src/Responses/Entities/Earn/Allocation/Allocations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Butschster\Kraken\Responses\Entities\Earn\Allocation;

use Brick\Math\BigDecimal;
use JMS\Serializer\Annotation\Type;

class Allocations
{
#[Type('string')]
public string $converted_asset;

#[Type(\Brick\Math\BigDecimal::class)]
public BigDecimal $total_allocated;

#[Type(\Brick\Math\BigDecimal::class)]
public BigDecimal $total_rewarded;

#[Type('string')]
public ?string $next_cursor = null;

#[Type("array<Butschster\Kraken\Responses\Entities\Earn\Allocation\Allocation>")]
public array $items = [];
}
11 changes: 11 additions & 0 deletions src/Responses/Entities/Earn/Allocation/AmountAllocated.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Butschster\Kraken\Responses\Entities\Earn\Allocation;

use JMS\Serializer\Annotation\Type;

class AmountAllocated
{
#[Type("Butschster\Kraken\Responses\Entities\Earn\Allocation\Total")]
public Total $total;
}
Loading