diff --git a/src/GraphQL/Traits/HasTokenInputRules.php b/src/GraphQL/Traits/HasTokenInputRules.php index 4506d89..2996ade 100644 --- a/src/GraphQL/Traits/HasTokenInputRules.php +++ b/src/GraphQL/Traits/HasTokenInputRules.php @@ -14,6 +14,8 @@ use Illuminate\Support\Arr; use Illuminate\Validation\Rule; use Enjin\Platform\Beam\Rules\BeamPackExistInBeam; +use Enjin\Platform\Beam\Rules\BeamPackMaxTokenCount; +use Enjin\Platform\Beam\Rules\BeamPackMaxTokenSupply; trait HasTokenInputRules { @@ -152,16 +154,17 @@ public function packTokenRules(array $args, ?string $collectionId = null, bool $ 'filled', 'integer', 'min:1', - new MaxTokenSupply($collectionId), + new BeamPackMaxTokenSupply($collectionId), ], 'packs.*.tokens.*.claimQuantity' => [ 'prohibited', ], - 'packs.claimQuantity' => [ + 'packs.*.claimQuantity' => [ 'bail', 'integer', 'min:1', 'max:1000', + new BeamPackMaxTokenCount($collectionId), ], ]; } diff --git a/src/Rules/BeamPackMaxTokenCount.php b/src/Rules/BeamPackMaxTokenCount.php new file mode 100644 index 0000000..23043ed --- /dev/null +++ b/src/Rules/BeamPackMaxTokenCount.php @@ -0,0 +1,13 @@ +data, 'packs'))->flatMap(fn ($row) => Arr::get($row, 'tokens', []))->toArray(); + } +} diff --git a/src/Rules/BeamPackMaxTokenSupply.php b/src/Rules/BeamPackMaxTokenSupply.php index 35c2573..cf03634 100644 --- a/src/Rules/BeamPackMaxTokenSupply.php +++ b/src/Rules/BeamPackMaxTokenSupply.php @@ -2,95 +2,12 @@ namespace Enjin\Platform\Beam\Rules; -use Closure; -use Enjin\Platform\Beam\Enums\BeamType; -use Enjin\Platform\Beam\Models\BeamClaim; -use Enjin\Platform\Models\Collection; -use Enjin\Platform\Models\TokenAccount; use Illuminate\Support\Arr; class BeamPackMaxTokenSupply extends MaxTokenSupply { - /** - * Determine if the validation rule passes. - * - * @param Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail - */ - public function validate(string $attribute, mixed $value, Closure $fail): void + protected function getInputTokens(): array { - /** - * The total circulating supply of tokens must not exceed the collection's maximum token supply. - * For example, if the maximum token count is 10 and the maximum token supply is 10, - * the total circulating supply must not exceed 100. - */ - if ($this->collectionId - && ($collection = Collection::firstWhere(['collection_chain_id' => $this->collectionId])) - && ! is_null($this->limit = $collection->max_token_supply) - ) { - if ((Arr::get($this->data, str_replace('tokenQuantityPerClaim', 'type', $attribute)) == BeamType::MINT_ON_DEMAND->name - && !$collection->max_token_supply >= $value) - || $this->limit == 0 - ) { - $fail($this->maxTokenSupplyMessage)->translate(['limit' => $this->limit]); - - return; - } - - if ($collection->max_token_count == 0) { - $fail('enjin-platform-beam::validation.max_token_count')->translate(['limit' => $this->limit]); - - return; - } - - $this->limit = $collection->max_token_supply * ($collection->max_token_count ?? 1); - - $balanceCount = TokenAccount::where('token_accounts.collection_id', $collection->id)->sum('balance'); - $claimCount = BeamClaim::where('type', BeamType::MINT_ON_DEMAND->name) - ->whereHas('beam', fn ($query) => $query->where('collection_chain_id', $this->collectionId)->where('end', '>', now())) - ->claimable() - ->sum('quantity'); - - $tokenCount = 0; - $tokenCount = collect($this->data['tokens']) - ->reduce(function ($carry, $token) { - - if (Arr::get($token, 'tokenIds')) { - return collect($token['tokenIds'])->reduce(function ($val, $tokenId) use ($token) { - $range = $this->integerRange($tokenId); - $claimQuantity = Arr::get($token, 'claimQuantity', 1); - $quantityPerClaim = Arr::get($token, 'tokenQuantityPerClaim', 1); - - return $val + ( - $range === false - ? $claimQuantity * $quantityPerClaim - : (($range[1] - $range[0]) + 1) * $claimQuantity * $quantityPerClaim - ); - }, $carry); - } - - if (Arr::get($token, 'tokenIdDataUpload')) { - $total = 0; - $handle = fopen($token['tokenIdDataUpload']->getPathname(), 'r'); - while (($line = fgets($handle)) !== false) { - $range = $this->integerRange(trim($line)); - $claimQuantity = Arr::get($token, 'claimQuantity', 1); - $quantityPerClaim = Arr::get($token, 'tokenQuantityPerClaim', 1); - $total += ( - $range === false - ? $claimQuantity * $quantityPerClaim - : (($range[1] - $range[0]) + 1) * $claimQuantity * $quantityPerClaim - ); - } - fclose($handle); - - return $total; - } - - }, $tokenCount); - - if ($this->limit < $balanceCount + $claimCount + $tokenCount) { - $fail($this->maxTokenSupplyMessage)->translate(['limit' => $this->limit]); - } - } + return collect(Arr::get($this->data, 'packs'))->flatMap(fn ($row) => Arr::get($row, 'tokens', []))->toArray(); } } diff --git a/src/Rules/MaxTokenCount.php b/src/Rules/MaxTokenCount.php index 597689b..cf0f7b0 100644 --- a/src/Rules/MaxTokenCount.php +++ b/src/Rules/MaxTokenCount.php @@ -39,7 +39,7 @@ public function validate(string $attribute, mixed $value, Closure $fail): void * The sum of all unique tokens (including existing tokens, tokens in beams, and tokens to be created) * must not exceed the collection's maximum token count. */ - if (!Arr::get($this->data, 'tokens')) { + if (!$inputTokens = $this->getInputTokens()) { return; } @@ -65,12 +65,12 @@ public function validate(string $attribute, mixed $value, Closure $fail): void ->groupBy('token_chain_id') ->count(); - $tokens = collect($this->data['tokens']) + $tokens = collect($inputTokens) ->filter(fn ($data) => !empty(Arr::get($data, 'tokenIds'))) ->pluck('tokenIds') ->flatten(); - collect($this->data['tokens']) + collect($inputTokens) ->filter(fn ($data) => !empty(Arr::get($data, 'tokenIdDataUpload'))) ->map(function ($data) use ($tokens) { $handle = fopen($data['tokenIdDataUpload']->getPathname(), 'r'); @@ -137,4 +137,9 @@ public function validate(string $attribute, mixed $value, Closure $fail): void } } } + + protected function getInputTokens(): array + { + return Arr::get($this->data, 'tokens', []); + } } diff --git a/src/Rules/MaxTokenSupply.php b/src/Rules/MaxTokenSupply.php index 2dd8a7e..a876a9e 100644 --- a/src/Rules/MaxTokenSupply.php +++ b/src/Rules/MaxTokenSupply.php @@ -49,7 +49,7 @@ public function validate(string $attribute, mixed $value, Closure $fail): void * For example, if the maximum token count is 10 and the maximum token supply is 10, * the total circulating supply must not exceed 100. */ - if (!Arr::get($this->data, 'tokens')) { + if (!$inputTokens = $this->getInputTokens()) { return; } @@ -81,7 +81,7 @@ public function validate(string $attribute, mixed $value, Closure $fail): void ->sum('quantity'); $tokenCount = 0; - $tokenCount = collect($this->data['tokens']) + $tokenCount = collect($inputTokens) ->reduce(function ($carry, $token) { if (Arr::get($token, 'tokenIds')) { @@ -123,4 +123,9 @@ public function validate(string $attribute, mixed $value, Closure $fail): void } } } + + protected function getInputTokens(): array + { + return Arr::get($this->data, 'tokens', []); + } } diff --git a/tests/Feature/GraphQL/Mutations/CreateBeamTest.php b/tests/Feature/GraphQL/Mutations/CreateBeamTest.php index 1eb349a..b726032 100644 --- a/tests/Feature/GraphQL/Mutations/CreateBeamTest.php +++ b/tests/Feature/GraphQL/Mutations/CreateBeamTest.php @@ -537,11 +537,11 @@ public function test_it_will_fail_with_invalid_token_quantity_per_claim(): void $response['error'] ); - // $response = $this->graphql($this->method, $this->generateBeamPackData(), true); - // $this->assertArraySubset( - // ['packs.0.tokens.0.tokenQuantityPerClaim' => ['The packs.0.tokens.0.tokenQuantityPerClaim is invalid, the amount provided is bigger than the token account balance.']], - // $response['error'] - // ); + $response = $this->graphql($this->method, $this->generateBeamPackData(), true); + $this->assertArraySubset( + ['packs.0.tokens.0.tokenQuantityPerClaim' => ['The packs.0.tokens.0.tokenQuantityPerClaim exceeded the maximum supply limit of 0 for unique tokens for this collection.']], + $response['error'] + ); } /**