Skip to content
Merged
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
1 change: 0 additions & 1 deletion assets/react/controllers/Contract/EditContract.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export default function EditContract() {
);
}
else{
console.log('Algo pasa', query.data.returnType, getReturnType(query.data.returnType));
const formValues: FormValues = {
...query.data,
token: query.data.tokenContract.code,
Expand Down
32 changes: 31 additions & 1 deletion assets/react/controllers/Contract/Form/ContractForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export interface FormValues {
minPerInvestment: number,
file?: FileList;
image?: FileList;
uri: string;
symbol: string;
};

interface CreateOrEditContractProps {
Expand Down Expand Up @@ -62,7 +64,9 @@ export default function ContractForm({ contract }: CreateOrEditContractProps) {
returnMonths: 12,
minPerInvestment: 10,
file: undefined as any,
image: undefined as any
image: undefined as any,
uri: "",
symbol: ""
},
});

Expand Down Expand Up @@ -99,6 +103,8 @@ export default function ContractForm({ contract }: CreateOrEditContractProps) {
formSendData.append('returnMonths', String(formData.returnMonths));
formSendData.append('returnType', String(formData.returnType));
formSendData.append('minPerInvestment', String(formData.minPerInvestment));
formSendData.append('uri', formData.uri);
formSendData.append('symbol', formData.symbol);

if(formData.file?.length > 0){
formSendData.append('file', formData.file[0]);
Expand Down Expand Up @@ -219,6 +225,30 @@ export default function ContractForm({ contract }: CreateOrEditContractProps) {
))}
</TextField>
</Grid2>
<Grid2 size={{ xs: 12, md: 6 }}>
<TextField
fullWidth
label="URI"
variant="outlined"
size="small"
placeholder="Metadata URI"
{...register('uri', { required: 'URI cannot be empty' })}
error={!!errors.uri}
helperText={errors.uri?.message}
/>
</Grid2>
<Grid2 size={{ xs: 12, md: 6 }}>
<TextField
fullWidth
label="Symbol"
variant="outlined"
size="small"
placeholder="Token symbol"
{...register('symbol', { required: 'Symbol cannot be empty' })}
error={!!errors.symbol}
helperText={errors.symbol?.message}
/>
</Grid2>
</Grid2>
<Typography variant="h5" sx={{ mb: 2, color: 'primary.main' }}>
Financial information
Expand Down
2 changes: 2 additions & 0 deletions assets/react/model/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export interface ContractOutput {
projectAddress: string,
muxedAccount?: string,
requiredReserveFunds?: number
uri: string,
symbol: string
}

export interface ContractWithdrawal {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"devDependencies": {
"@babel/preset-react": "^7.24.7",
"@hotwired/stimulus": "^3.0.0",
"@hotwired/turbo": "^7.1.1 || ^8.0",
"@hotwired/turbo": ">=8.0.21",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/ux-react": "file:vendor/symfony/ux-react/assets",
"@symfony/webpack-encore": "github:symfony/webpack-encore",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public function fromEntityToOutputDto(Contract $contract, ?ContractBalance $cont
$returnType,
$contract->getReturnMonths(),
$contract->getProjectAddress(),
$contract->getUri(),
$contract->getSymbol(),
$contract->getMuxedAccount(),
$requiredReserveFunds
);
Expand Down Expand Up @@ -99,6 +101,8 @@ public function fromCreateInvestmentContractInputDtoToEntity(CreateContractDto $
$contract->setReturnType((int) $createContractDto->returnType);
$contract->setProjectAddress($createContractDto->projectAddress);
$contract->setOrganzation($user->getOrganization());
$contract->setUri($createContractDto->uri);
$contract->setSymbol($createContractDto->symbol);

return $contract;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function mapToEntity(array $trxResult, UserContract $userContract): void
foreach ($trxResult as $key => $value) {
$result = match ($key) {
'accumulated_interests', 'deposited', 'total', 'paid', 'regular_payment','commission' => I128::fromLoAndHi($value->getLo(), $value->getHi())->toPhp($decimals),
'claimable_ts' => $value,
'claimable_ts', 'token_id' => $value,
'last_transfer_ts' => ($value > 0) ? new \DateTimeImmutable(date('Y-m-d H:i:s', $value)) : null,
'status' => (UserContractStatus::tryFrom($value) ?? UserContractStatus::UNKNOWN)->name,
default => null,
Expand All @@ -41,6 +41,7 @@ private function setValueToEntity(UserContract $userContract, string $key, mixed
'paid' => $userContract->setTotalCharged($currentTotalCharged + $value),
'status' => $userContract->setStatus($value),
'regular_payment' => $userContract->setRegularPayment($value),
'token_id' => $userContract->setTokenId($value),
default => null,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
namespace App\Blockchain\Stellar\Soroban\ScContract\Operation\Builder;

use App\Blockchain\Stellar\Account\StellarAccountLoader;
use App\Domain\Token\Service\TokenNormalizer;
use App\Domain\UserContract\Service\ClaimableDateCalculator;
use App\Domain\Contract\Service\ContractActivationInvestmentParamsBuilder;
use App\Entity\Contract\Contract;
use Soneso\StellarSDK\CreateContractWithConstructorHostFunction;
use Soneso\StellarSDK\InvokeHostFunctionOperation;
Expand All @@ -18,31 +17,23 @@
class ContractActivationOperationBuilder
{
public function __construct(
private readonly ClaimableDateCalculator $claimableDateCalculator,
private readonly TokenNormalizer $tokenNormalizer,
private readonly StellarAccountLoader $stellarAccountLoader,
private readonly ContractActivationInvestmentParamsBuilder $contractActivationInvestmentParamsBuilder
) {
}

public function build(Contract $contract, string $wasmId): InvokeHostFunctionOperation
{
$claimMonts = $contract->getClaimMonths();
$days = $this->claimableDateCalculator->getDaysToClaim($claimMonts);
$rate = $contract->getRate() * 100;

$goalI128 = $this->tokenNormalizer->normalizeTokenValue($contract->getGoal(), $contract->getToken()->getDecimals());
$minPerInvestmentI128 = $this->tokenNormalizer->normalizeTokenValue($contract->getMinPerInvestment(), $contract->getToken()->getDecimals());
$investmentParams = $this->contractActivationInvestmentParamsBuilder->buildInvestmentParams($contract);

$constructorArgs = [
Address::fromAccountId($this->stellarAccountLoader->getAccount()->getAccountId())->toXdrSCVal(),
Address::fromAccountId($contract->getProjectAddress())->toXdrSCVal(),
Address::fromContractId($contract->getToken()->getAddress())->toXdrSCVal(),
XdrSCVal::forU32((int) $rate),
XdrSCVal::forU64($days),
XdrSCVal::forI128Parts($goalI128->getHi(), $goalI128->getLo()),
XdrSCVal::forU32($contract->getReturnType()),
XdrSCVal::forU32($contract->getReturnMonths()),
XdrSCVal::forI128Parts($minPerInvestmentI128->getHi(), $minPerInvestmentI128->getLo()),
XdrSCVal::forString($contract->getUri()),
XdrSCVal::forString($contract->getLabel()),
XdrSCVal::forString($contract->getSymbol()),
$investmentParams,
];

$createContractHostFunction = new CreateContractWithConstructorHostFunction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@
use Soneso\StellarSDK\InvokeContractHostFunction;
use Soneso\StellarSDK\InvokeHostFunctionOperation;
use Soneso\StellarSDK\InvokeHostFunctionOperationBuilder;
use Soneso\StellarSDK\Soroban\Address;
use Soneso\StellarSDK\Xdr\XdrSCVal;

class PayUserContractOperationBuilder
{
public function build(UserContract $userContract): InvokeHostFunctionOperation
{
$invokeContractHostFunction = new InvokeContractHostFunction($userContract->getContract()->getAddress(), ContractFunctions::process_investor_payment->name, [
Address::fromAccountId($userContract->getUserWallet()->getAddress())->toXdrSCVal(),
XdrSCVal::forU64($userContract->getClaimableTs()),
XdrSCVal::forU32($userContract->getTokenId()),
]);
$builder = new InvokeHostFunctionOperationBuilder($invokeContractHostFunction);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace App\Domain\Contract\Service;

use App\Domain\Token\Service\TokenNormalizer;
use App\Domain\UserContract\Service\ClaimableDateCalculator;
use App\Entity\Contract\Contract;
use Soneso\StellarSDK\Xdr\XdrSCMapEntry;
use Soneso\StellarSDK\Xdr\XdrSCVal;

class ContractActivationInvestmentParamsBuilder
{
const CLAIM_BLOCK_DAYS_KEY = 'claim_block_days';
const GOAL_KEY = 'goal';
const I_RATE_KEY = 'i_rate';
const MIN_PER_INVESTMENT_KEY = 'min_per_investment';
const RETURN_MONTHS_KEY = 'return_months';
const RETURN_TYPE_KEY = 'return_type';

public function __construct(
private readonly ClaimableDateCalculator $claimableDateCalculator,
private readonly TokenNormalizer $tokenNormalizer
) {
}

public function buildInvestmentParams(Contract $contract): XdrSCVal
{
$claimMonths = $contract->getClaimMonths();
$days = $this->claimableDateCalculator->getDaysToClaim($claimMonths);
$rate = $contract->getRate() * 100;

$goalI128 = $this->tokenNormalizer->normalizeTokenValue($contract->getGoal(), $contract->getToken()->getDecimals());
$minPerInvestmentI128 = $this->tokenNormalizer->normalizeTokenValue($contract->getMinPerInvestment(), $contract->getToken()->getDecimals());

return XdrSCVal::forMap([
new XdrSCMapEntry(
XdrSCVal::forSymbol(self::CLAIM_BLOCK_DAYS_KEY),
XdrSCVal::forU64($days)
),
new XdrSCMapEntry(
XdrSCVal::forSymbol(self::GOAL_KEY),
XdrSCVal::forI128Parts($goalI128->getHi(), $goalI128->getLo())
),
new XdrSCMapEntry(
XdrSCVal::forSymbol(self::I_RATE_KEY),
XdrSCVal::forU32((int) $rate)
),
new XdrSCMapEntry(
XdrSCVal::forSymbol(self::MIN_PER_INVESTMENT_KEY),
XdrSCVal::forI128Parts($minPerInvestmentI128->getHi(), $minPerInvestmentI128->getLo())
),
new XdrSCMapEntry(
XdrSCVal::forSymbol(self::RETURN_MONTHS_KEY),
XdrSCVal::forU32($contract->getReturnMonths())
),
new XdrSCMapEntry(
XdrSCVal::forSymbol(self::RETURN_TYPE_KEY),
XdrSCVal::forU32($contract->getReturnType())
),
]);
}
}
30 changes: 30 additions & 0 deletions src/Entity/Contract/Contract.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ class Contract
#[ORM\Column(nullable: true)]
private ?int $muxedId = null;

#[ORM\Column(length: 255)]
private ?string $uri = null;

#[ORM\Column(length: 10)]
private ?string $symbol = null;

public function __construct()
{
$this->contractBalances = new ArrayCollection();
Expand Down Expand Up @@ -568,4 +574,28 @@ public function setMuxedId(?int $muxedId): static

return $this;
}

public function getUri(): ?string
{
return $this->uri;
}

public function setUri(string $uri): static
{
$this->uri = $uri;

return $this;
}

public function getSymbol(): ?string
{
return $this->symbol;
}

public function setSymbol(string $symbol): static
{
$this->symbol = $symbol;

return $this;
}
}
15 changes: 15 additions & 0 deletions src/Entity/Contract/UserContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class UserContract
#[ORM\Column(nullable: true)]
private ?float $realDeposited = null;

#[ORM\Column(nullable: true)]
private ?int $tokenId = null;

public function __construct()
{
$this->payments = new ArrayCollection();
Expand Down Expand Up @@ -271,4 +274,16 @@ public function setRealDeposited(?float $realDeposited): static

return $this;
}

public function getTokenId(): ?int
{
return $this->tokenId;
}

public function setTokenId(int $tokenId): static
{
$this->tokenId = $tokenId;

return $this;
}
}
8 changes: 8 additions & 0 deletions src/Presentation/Contract/DTO/Input/CreateContractDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Validator\Constraints\GreaterThan;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Url;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class CreateContractDto
Expand Down Expand Up @@ -55,6 +56,13 @@ public function __construct(

#[NotBlank(message: 'Return months cannot be empty')]
public readonly string|int $returnMonths,

#[NotBlank(message: 'Return months cannot be empty')]
#[Url(message: 'URI must be a valid URL')]
public readonly string $uri,

#[NotBlank(message: 'Return months cannot be empty')]
public readonly string $symbol,
) {
}

Expand Down
2 changes: 2 additions & 0 deletions src/Presentation/Contract/DTO/Output/ContractDtoOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public function __construct(
public string $returnType,
public int $returnMonths,
public string $projectAddress,
public string $uri,
public string $symbol,
public ?string $muxedAccount = null,
public ?float $requiredReserveFunds = null
) {
Expand Down
4 changes: 4 additions & 0 deletions tests/EntityGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public static function createApprovedContract(User $issuer, Token $token): Contr
$contract->setShortDescription('A contract');
$contract->setStatus('APPROVED');
$contract->setOrganzation($issuer->getOrganization());
$contract->setUri('https://example.com');
$contract->setSymbol('EXPM');

return $contract;
}
Expand Down Expand Up @@ -128,6 +130,8 @@ public static function createActiveContract(User $issuer, Token $token): Contrac
$contract->setShortDescription('A contract');
$contract->setStatus('ACTIVE');
$contract->setOrganzation($issuer->getOrganization());
$contract->setUri('https://example.com');
$contract->setSymbol('EXPM');

return $contract;
}
Expand Down
Binary file modified wasm/investment.wasm
Binary file not shown.