Skip to content

Commit

Permalink
[PLA-1734][PLA-1743] Fixes WhitelistedPallet, replaces IsFuelTankOwn…
Browse files Browse the repository at this point in the history
…er by CanDispatch (#42)
  • Loading branch information
leonardocustodio committed Apr 28, 2024
1 parent 4624d5c commit ddb5b18
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 14 deletions.
2 changes: 2 additions & 0 deletions lang/en/validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
'valid_mutation.encodedData' => 'The id and encodedData attribute must be queried from the result.',
'rule_set_not_exist' => 'The rule set ID doesn\'t exist.',
'rule_set_exist' => 'The rule set ID already exist.',
'dispatch_rule_not_found' => 'The dispatch rule chosen was not found.',
'dispatch_rule_requirements' => 'The dispatch rule requirements are not met.',
];
8 changes: 6 additions & 2 deletions src/GraphQL/Mutations/DispatchMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
use Enjin\BlockchainTools\HexConverter;
use Enjin\Platform\FuelTanks\Enums\DispatchCall;
use Enjin\Platform\FuelTanks\Exceptions\FuelTanksException;
use Enjin\Platform\FuelTanks\Rules\IsFuelTankOwner;
use Enjin\Platform\FuelTanks\Rules\CanDispatch;
use Enjin\Platform\FuelTanks\Rules\FuelTankExists;
use Enjin\Platform\FuelTanks\Rules\RuleSetExists;
use Enjin\Platform\FuelTanks\Rules\ValidMutation;
use Enjin\Platform\GraphQL\Schemas\Primary\Substrate\Traits\StoresTransactions;
Expand Down Expand Up @@ -156,14 +157,17 @@ protected function rulesWithValidation(array $args): array
'filled',
'max:255',
new ValidSubstrateAddress(),
new IsFuelTankOwner(),
new FuelTankExists(),
],
'ruleSetId' => [
'bail',
new MinBigInt(),
new MaxBigInt(Hex::MAX_UINT32),
new RuleSetExists(),
],
'dispatch' => [
new CanDispatch(),
],
'dispatch.query' => [
'filled',
new ValidMutation(),
Expand Down
5 changes: 5 additions & 0 deletions src/Models/Substrate/MaxFuelBurnPerTransactionParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,9 @@ public function toArray(): array
'MaxFuelBurnPerTransaction' => $this->max,
];
}

public function validate(string $value): bool
{
return true;
}
}
5 changes: 5 additions & 0 deletions src/Models/Substrate/PermittedCallsParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ public function toArray(): array
'PermittedCalls' => $this->calls,
];
}

public function validate(string $value): bool
{
return true;
}
}
5 changes: 5 additions & 0 deletions src/Models/Substrate/PermittedExtrinsicsParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ public function toEncodable(): array
];
}

public function validate(string $value): bool
{
return true;
}

protected function getEncodedData(string $mutationName): string
{
$transactionMutation = Package::getClassesThatImplementInterface(PlatformBlockchainTransaction::class)
Expand Down
31 changes: 31 additions & 0 deletions src/Models/Substrate/RequireTokenParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace Enjin\Platform\FuelTanks\Models\Substrate;

use Enjin\Platform\Models\Collection;
use Enjin\Platform\Models\Token;
use Enjin\Platform\Models\TokenAccount;
use Facades\Enjin\Platform\Services\Database\WalletService;
use Illuminate\Support\Arr;

class RequireTokenParams extends FuelTankRules
Expand Down Expand Up @@ -47,4 +51,31 @@ public function toArray(): array
'tokenId' => $this->tokenId,
]];
}

public function validate(string $caller): bool
{
if (!($collection = Collection::firstWhere('collection_chain_id', $this->collectionId))) {
return false;
}

if (!($token = Token::firstWhere([
'collection_id' => $collection->id,
'token_chain_id' => $this->tokenId,
]))) {
return false;
}

$wallet = WalletService::firstOrStore([
'public_key' => $caller,
]);

if (!($tokenAccount = TokenAccount::firstWhere([
'wallet_id' => $wallet->id,
'token_id' => $token->id,
]))) {
return false;
}

return $tokenAccount->balance > 0;
}
}
5 changes: 5 additions & 0 deletions src/Models/Substrate/TankFuelBudgetParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ public function toArray(): array
],
];
}

public function validate(string $value): bool
{
return true;
}
}
5 changes: 5 additions & 0 deletions src/Models/Substrate/UserFuelBudgetParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@ public function toArray(): array
],
];
}

public function validate(string $value): bool
{
return true;
}
}
5 changes: 5 additions & 0 deletions src/Models/Substrate/WhitelistedCallersParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ public function toArray(): array
'WhitelistedCallers' => $this->callers,
];
}

public function validate(string $caller): bool
{
return in_array($caller, $this->callers);
}
}
5 changes: 5 additions & 0 deletions src/Models/Substrate/WhitelistedCollectionsParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ public function toArray(): array
'WhitelistedCollections' => $this->collections,
];
}

public function validate(string $value): bool
{
return true;
}
}
10 changes: 9 additions & 1 deletion src/Models/Substrate/WhitelistedPalletsParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Enjin\BlockchainTools\HexConverter;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class WhitelistedPalletsParams extends FuelTankRules
{
Expand All @@ -22,7 +23,7 @@ public static function fromEncodable(array $params): self
{
return new self(
pallets: array_map(
fn ($pallet) => HexConverter::hexToString($pallet),
fn ($pallet) => is_array($pallet) ? array_key_first($pallet) : HexConverter::hexToString($pallet),
Arr::get($params, 'WhitelistedPallets', []),
),
);
Expand All @@ -47,4 +48,11 @@ public function toArray(): array
'WhitelistedPallets' => $this->pallets,
];
}

public function validate(string $pallet): bool
{
$hasPallet = array_filter($this->pallets, fn ($v) => Str::lower($pallet) === Str::snake($v));

return count($hasPallet) > 0;
}
}
133 changes: 133 additions & 0 deletions src/Rules/CanDispatch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

namespace Enjin\Platform\FuelTanks\Rules;

use Closure;
use Enjin\Platform\FuelTanks\Enums\DispatchRule;
use Enjin\Platform\FuelTanks\Models\FuelTank;
use Enjin\Platform\FuelTanks\Models\Substrate\MaxFuelBurnPerTransactionParams;
use Enjin\Platform\FuelTanks\Models\Substrate\PermittedCallsParams;
use Enjin\Platform\FuelTanks\Models\Substrate\PermittedExtrinsicsParams;
use Enjin\Platform\FuelTanks\Models\Substrate\RequireTokenParams;
use Enjin\Platform\FuelTanks\Models\Substrate\TankFuelBudgetParams;
use Enjin\Platform\FuelTanks\Models\Substrate\UserFuelBudgetParams;
use Enjin\Platform\FuelTanks\Models\Substrate\WhitelistedCallersParams;
use Enjin\Platform\FuelTanks\Models\Substrate\WhitelistedCollectionsParams;
use Enjin\Platform\FuelTanks\Models\Substrate\WhitelistedPalletsParams;
use Enjin\Platform\Rules\Traits\HasDataAwareRule;
use Enjin\Platform\Support\Account;
use Enjin\Platform\Support\SS58Address;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Arr;

class CanDispatch implements DataAwareRule, ValidationRule
{
use HasDataAwareRule;

/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$fuelTank = FuelTank::where('public_key', SS58Address::getPublicKey(Arr::get($this->data, 'tankId')))
->with('owner')
->first();

if (!$fuelTank) {
$fail(__('validation.exists', ['attribute' => $attribute]))->translate();

return;
}

$caller = SS58Address::getPublicKey(Arr::get($this->data, 'signingAccount') ?? Account::daemonPublicKey());
$ruleSetRules = $fuelTank->dispatchRules()->where('rule_set_id', Arr::get($this->data, 'ruleSetId'))->get();

if ($ruleSetRules->isEmpty()) {
$fail(__('enjin-platform-fuel-tanks::validation.dispatch_rule_not_found'))->translate();

return;
}

$canDispatch = $ruleSetRules->filter(function ($ruleSetRule) use ($caller) {
$ruleType = Arr::get($ruleSetRule, 'rule');
$value = Arr::get($ruleSetRule, 'value');

return $this->canDispatchWithRule($caller, $ruleType, $value);
});

if ($canDispatch->count() < $ruleSetRules->count()) {
$fail(__('enjin-platform-fuel-tanks::validation.dispatch_rule_requirements'))->translate();
}
}

protected function canDispatchWithRule(string $caller, string $ruleType, mixed $value): bool
{
switch ($ruleType) {
case DispatchRule::WHITELISTED_CALLERS->value:
$dispatchRule = new WhitelistedCallersParams($value);

return $dispatchRule->validate($caller);

case DispatchRule::REQUIRE_TOKEN->value:
$dispatchRule = new RequireTokenParams($value['collectionId'], $value['tokenId']);

return $dispatchRule->validate($caller);

case DispatchRule::WHITELISTED_PALLETS->value:
$dispatchRule = new WhitelistedPalletsParams($value);

return $dispatchRule->validate($this->data['dispatch']['call']);

case DispatchRule::PERMITTED_CALLS->value:
$dispatchRule = new PermittedCallsParams($value);

// TODO: Not sure how to check the above yet
return $dispatchRule->validate($caller);

case DispatchRule::PERMITTED_EXTRINSICS->value:
$dispatchRule = new PermittedExtrinsicsParams(array_map(function ($x) {
$extrinsic = explode('.', $x);

return [
$extrinsic[0] => [
$extrinsic[1] => null,
],
];
}, $value));

// TODO: Not sure how to check the above yet
return $dispatchRule->validate($caller);

case DispatchRule::WHITELISTED_COLLECTIONS->value:
$dispatchRule = new WhitelistedCollectionsParams($value);

// TODO: Not sure how to check the above yet
return $dispatchRule->validate($caller);

case DispatchRule::MAX_FUEL_BURN_PER_TRANSACTION->value:
$dispatchRule = new MaxFuelBurnPerTransactionParams($value);

// TODO: Not sure how to calculate the above yet
return $dispatchRule->validate($caller);

case DispatchRule::TANK_FUEL_BUDGET->value:
$dispatchRule = new TankFuelBudgetParams($value['amount'], $value['resetPeriod']);

// TODO: Not sure how to calculate the above yet
return $dispatchRule->validate($caller);

case DispatchRule::USER_FUEL_BUDGET->value:
$dispatchRule = new UserFuelBudgetParams($value['amount'], $value['resetPeriod']);

// TODO: Not sure how to calculate the above yet
return $dispatchRule->validate($caller);

default:
return true;

}
}
}
14 changes: 3 additions & 11 deletions tests/Feature/GraphQL/Mutations/DispatchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,6 @@ public function test_it_will_fail_with_invalid_parameter_tank_id(): void
]
);
$tank->forceFill(['owner_wallet_id' => $wallet->id])->save();
$response = $this->graphql(
$this->method,
array_merge($data, ['tankId' => $tank->public_key]),
true
);
$this->assertArraySubset(
['tankId' => ['The tank id provided is not owned by you.']],
$response['error']
);
}

public function test_it_will_fail_with_invalid_parameter_rule_set_id(): void
Expand Down Expand Up @@ -177,11 +168,11 @@ public function test_it_will_fail_with_invalid_parameter_rule_set_id(): void
array_merge($data, ['ruleSetId' => Hex::MAX_UINT128]),
true
);
$this->assertEquals(

$this->assertArraySubset(
['ruleSetId' => ['The rule set id is too large, the maximum value it can be is 4294967295.']],
$response['error']
);

$response = $this->graphql(
$this->method,
array_merge($data, ['ruleSetId' => fake()->numberBetween(5000, 10000)]),
Expand Down Expand Up @@ -253,6 +244,7 @@ public function test_it_will_fail_with_invalid_parameter_dispatch(): void

Arr::set($invalidData, 'dispatch.variables', null);
$response = $this->graphql($this->method, $invalidData, true);

$this->assertEquals(
"There's an error with the query. Please check the query and try again.",
$response['error']
Expand Down

0 comments on commit ddb5b18

Please sign in to comment.