110 lines
4.1 KiB
PHP
110 lines
4.1 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Contractless\Rpc\Transaction;
|
||
|
|
|
||
|
|
use Contractless\Rpc\Crypto\CryptoInterface;
|
||
|
|
use Contractless\Rpc\Exception\ProtocolException;
|
||
|
|
use Contractless\Rpc\Protocol\Address;
|
||
|
|
use Contractless\Rpc\Protocol\Binary;
|
||
|
|
use Contractless\Rpc\Wallet\Credentials;
|
||
|
|
|
||
|
|
final class AgreementBuilder
|
||
|
|
{
|
||
|
|
public function __construct(
|
||
|
|
private readonly CryptoInterface $crypto,
|
||
|
|
private readonly Credentials $credentials,
|
||
|
|
) {
|
||
|
|
}
|
||
|
|
|
||
|
|
public function swap(
|
||
|
|
int $expiration,
|
||
|
|
string $ticker1,
|
||
|
|
int $series1,
|
||
|
|
int $value1,
|
||
|
|
string $ticker2,
|
||
|
|
int $series2,
|
||
|
|
int $value2,
|
||
|
|
string $sender1,
|
||
|
|
string $sender2,
|
||
|
|
int $tip1,
|
||
|
|
int $tip2,
|
||
|
|
int $fee1,
|
||
|
|
int $fee2,
|
||
|
|
?int $timestamp = null,
|
||
|
|
): DualSignedTransaction {
|
||
|
|
$timestamp ??= time();
|
||
|
|
$ticker1 = Binary::fixedText($ticker1, 15, 'First swap asset');
|
||
|
|
$ticker2 = Binary::fixedText($ticker2, 15, 'Second swap asset');
|
||
|
|
$unsigned = [
|
||
|
|
'txtype' => 6, 'timestamp' => $timestamp, 'offer_expiration' => $expiration,
|
||
|
|
'ticker1' => $ticker1, 'nft_series1' => $series1, 'value1' => $value1,
|
||
|
|
'ticker2' => $ticker2, 'nft_series2' => $series2, 'value2' => $value2,
|
||
|
|
'sender1' => $sender1, 'sender2' => $sender2, 'tip1' => $tip1,
|
||
|
|
'tip2' => $tip2, 'txfee1' => $fee1, 'txfee2' => $fee2,
|
||
|
|
];
|
||
|
|
$json = $this->json($unsigned);
|
||
|
|
$hash = $this->crypto->skein256($json);
|
||
|
|
$bytes = Binary::u8(6) . Binary::u32($timestamp) . Binary::u32($expiration)
|
||
|
|
. $ticker1 . Binary::u32($series1) . Binary::u64($value1)
|
||
|
|
. $ticker2 . Binary::u32($series2) . Binary::u64($value2)
|
||
|
|
. Address::toBytes($sender1) . Address::toBytes($sender2)
|
||
|
|
. Binary::u64($tip1) . Binary::u64($tip2)
|
||
|
|
. Binary::u64($fee1) . Binary::u64($fee2);
|
||
|
|
return (new DualSignedTransaction($json, $bytes, $hash))
|
||
|
|
->signNext($this->crypto, $this->credentials);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function loan(
|
||
|
|
string $loanCoin,
|
||
|
|
int $loanAmount,
|
||
|
|
string $lender,
|
||
|
|
string $collateral,
|
||
|
|
int $collateralAmount,
|
||
|
|
string $borrower,
|
||
|
|
string $paymentPeriod,
|
||
|
|
int $paymentNumber,
|
||
|
|
int $paymentAmount,
|
||
|
|
int $gracePeriod,
|
||
|
|
int $maxLateValue,
|
||
|
|
int $fee,
|
||
|
|
?int $timestamp = null,
|
||
|
|
): DualSignedTransaction {
|
||
|
|
$timestamp ??= time();
|
||
|
|
$loanCoin = Binary::fixedText($loanCoin, 15, 'Loan asset');
|
||
|
|
$collateral = Binary::fixedText($collateral, 21, 'Collateral asset');
|
||
|
|
if (strlen($paymentPeriod) !== 1) {
|
||
|
|
throw new ProtocolException('Payment period must be one byte: d, w, or m.');
|
||
|
|
}
|
||
|
|
$unsigned = [
|
||
|
|
'txtype' => 7, 'timestamp' => $timestamp, 'loan_coin' => $loanCoin,
|
||
|
|
'loan_amount' => $loanAmount, 'lender' => $lender,
|
||
|
|
'collateral' => $collateral, 'collateral_amount' => $collateralAmount,
|
||
|
|
'borrower' => $borrower, 'payment_period' => $paymentPeriod,
|
||
|
|
'payment_number' => $paymentNumber, 'payment_amount' => $paymentAmount,
|
||
|
|
'grace_period' => $gracePeriod, 'max_late_value' => $maxLateValue,
|
||
|
|
'txfee' => $fee,
|
||
|
|
];
|
||
|
|
$json = $this->json($unsigned);
|
||
|
|
$hash = $this->crypto->skein256($json);
|
||
|
|
$bytes = Binary::u8(7) . Binary::u32($timestamp) . $loanCoin
|
||
|
|
. Binary::u64($loanAmount) . Address::toBytes($lender)
|
||
|
|
. $collateral . Binary::u64($collateralAmount)
|
||
|
|
. Address::toBytes($borrower) . $paymentPeriod
|
||
|
|
. Binary::u8($paymentNumber) . Binary::u64($paymentAmount)
|
||
|
|
. Binary::u8($gracePeriod) . Binary::u64($maxLateValue)
|
||
|
|
. Binary::u64($fee);
|
||
|
|
return (new DualSignedTransaction($json, $bytes, $hash, storesHash: true))
|
||
|
|
->signNext($this->crypto, $this->credentials);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function json(array $unsigned): string
|
||
|
|
{
|
||
|
|
return json_encode(
|
||
|
|
$unsigned,
|
||
|
|
JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|