Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PLA-1878] Mutation support for v1010 #57

Merged
merged 4 commits into from
Jul 5, 2024
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
4 changes: 1 addition & 3 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
name: Run Tests
name: Unit & Functional Tests

on:
pull_request:
paths-ignore:
- "**.md"
push:
paths-ignore:
- "**.md"
Expand Down
58 changes: 58 additions & 0 deletions .github/workflows/sast.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Static Application Security Testing

on:
pull_request:
push:
paths-ignore:
- "**.md"

jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8
env:
MYSQL_DATABASE: platform
MYSQL_ROOT_PASSWORD: password
ports:
- 33306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
redis:
image: redis:7
ports:
- 6379:6379
options: --entrypoint redis-server
strategy:
fail-fast: true
matrix:
php: [8.2]

name: PHP ${{ matrix.php }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, gmp, intl, json, mysql, readline, sodium, bcmath, pcov
tools: composer:v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Setup problem matchers
run: |
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Install dependencies
run: |
composer install --no-interaction --no-progress
composer dump-autoload

- name: Run Rector
run: |
./vendor/bin/rector process --dry-run
2 changes: 0 additions & 2 deletions .github/workflows/security_checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: Dependencies Security Checker

on:
pull_request:
paths-ignore:
- '**.md'
push:
paths-ignore:
- '**.md'
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
}
],
"require": {
"php": "^8.2",
"php": "^8.2|^8.3",
"ext-bcmath": "*",
"ext-json": "*",
"ext-openssl": "*",
Expand All @@ -41,6 +41,7 @@
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/php-code-coverage": "^10.0",
"phpunit/phpunit": "^10.0",
"rector/rector": "^1.0",
"roave/security-advisories": "dev-latest"
},
"autoload": {
Expand All @@ -60,7 +61,8 @@
"scripts": {
"build-sr25519": "cd vendor/gmajor/sr25519-bindings/go && go build -buildmode=c-shared -o sr25519.so . && mv sr25519.so ../src/Crypto/sr25519.so",
"analyse": "vendor/bin/phpstan analyse",
"fix": "vendor/bin/pint",
"dry-fix": "vendor/bin/rector process --dry-run && vendor/bin/pint --test --config ./pint.json",
"fix": "vendor/bin/rector process && vendor/bin/pint --config ./pint.json",
"test": "vendor/bin/phpunit",
"test-coverage": "vendor/bin/phpunit --coverage-html ../../temp/coverage",
"post-autoload-dump": [
Expand Down
17 changes: 17 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;

return RectorConfig::configure()
->withPaths([
__DIR__ . '/config',
__DIR__ . '/lang',
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withPhpSets(php82: true)
->withPreparedSets(deadCode: true)
->withRules([Spatie\Ray\Rector\RemoveRayCallRector::class])
->withTypeCoverageLevel(0);
25 changes: 21 additions & 4 deletions src/GraphQL/Mutations/CreateListingMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public function args(): array
'type' => GraphQL::type('String'),
'description' => __('enjin-platform-marketplace::type.marketplace_listing.field.salt'),
],
// TODO: We should remove `auctionData` and replace it with `listingData`
// listingData = FixedPrice, Auction, Offer
// FixedPrice => null,
// Auction => { startBlock, endBlock },
// Offer => { expiration }
'auctionData' => [
'type' => GraphQL::type('AuctionDataInputType'),
'description' => __('enjin-platform-marketplace::input_type.auction_data.description'),
Expand All @@ -106,7 +111,8 @@ public function resolve(
ResolveInfo $resolveInfo,
Closure $getSelectFields,
) {
$encodedData = TransactionSerializer::encode($this->getMutationName(), static::getEncodableParams(
$method = isRunningLatest() ? $this->getMutationName() . 'V1010' : $this->getMutationName();
$encodedData = TransactionSerializer::encode($method, static::getEncodableParams(
makeAssetId: new MultiTokensTokenAssetIdParams(
Arr::get($args, 'makeAssetId.collectionId'),
$this->encodeTokenId(Arr::get($args, 'makeAssetId'))
Expand Down Expand Up @@ -136,15 +142,26 @@ public static function getEncodableParams(...$params): array
$amount = Arr::get($params, 'amount', 0);
$price = Arr::get($params, 'price', 0);
$salt = Arr::get($params, 'salt', Str::random(10));
$auctionData = Arr::get($params, 'auctionData', null);
$auctionData = Arr::get($params, 'auctionData');

$extra = isRunningLatest() ? [
'listingData' => $auctionData ? [
'Auction' => $auctionData->toEncodable(),
] : [
'FixedPrice' => null,
],
] : [
'auctionData' => $auctionData?->toEncodable(),
];

return [
'makeAssetId' => $makeAsset->toEncodable(),
'takeAssetId' => $takeAsset->toEncodable(),
'amount' => gmp_init($amount),
'price' => gmp_init($price),
'salt' => HexConverter::stringToHexPrefixed($salt),
'auctionData' => $auctionData?->toEncodable(),
...$extra,
'depositor' => null,
];
}

Expand All @@ -158,7 +175,7 @@ protected function makeOrTakeRuleExist(?string $collectionId = null, ?bool $isMa
'required_with:' . $makeOrTake . '.tokenId',
new MinBigInt(),
new MaxBigInt(Hex::MAX_UINT128),
function (string $attribute, mixed $value, Closure $fail) {
function (string $attribute, mixed $value, Closure $fail): void {
if (!Collection::where('collection_chain_id', $value)->exists()) {
$fail('validation.exists')->translate();
}
Expand Down
60 changes: 26 additions & 34 deletions src/GraphQL/Types/MarketplaceListingType.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,21 @@ public function fields(): array
'makeAssetId' => [
'type' => GraphQL::type('Asset!'),
'description' => __('enjin-platform-marketplace::type.marketplace_listing.field.makeAssetId'),
'resolve' => function ($listing) {
return [
'collectionId' => $listing->make_collection_chain_id,
'tokenId' => $listing->make_token_chain_id,
];
},
'resolve' => fn ($listing) => [
'collectionId' => $listing->make_collection_chain_id,
'tokenId' => $listing->make_token_chain_id,
],
'is_relation' => false,
'selectable' => false,
'always' => ['make_collection_chain_id', 'make_token_chain_id'],
],
'takeAssetId' => [
'type' => GraphQL::type('Asset!'),
'description' => __('enjin-platform-marketplace::type.marketplace_listing.field.takeAssetId'),
'resolve' => function ($listing) {
return [
'collectionId' => $listing->take_collection_chain_id,
'tokenId' => $listing->take_token_chain_id,
];
},
'resolve' => fn ($listing) => [
'collectionId' => $listing->take_collection_chain_id,
'tokenId' => $listing->take_token_chain_id,
],
'is_relation' => false,
'selectable' => false,
'always' => ['take_collection_chain_id', 'take_token_chain_id'],
Expand Down Expand Up @@ -120,34 +116,30 @@ public function fields(): array
'description' => __('enjin-platform-marketplace::type.marketplace_sale.description'),
'args' => ConnectionInput::args(),
'is_relation' => true,
'resolve' => function ($listing, $args) {
return [
'items' => new CursorPaginator(
$listing?->sales,
$args['first'],
Arr::get($args, 'after') ? Cursor::fromEncoded($args['after']) : null,
['parameters' => ['id']]
),
'total' => (int) $listing?->sales_count,
];
},
'resolve' => fn ($listing, $args) => [
'items' => new CursorPaginator(
$listing?->sales,
$args['first'],
Arr::get($args, 'after') ? Cursor::fromEncoded($args['after']) : null,
['parameters' => ['id']]
),
'total' => (int) $listing?->sales_count,
],
],
'bids' => [
'type' => GraphQL::paginate('MarketplaceBid', 'MarketplaceBidConnection'),
'description' => __('enjin-platform-marketplace::type.marketplace_bid.description'),
'args' => ConnectionInput::args(),
'is_relation' => true,
'resolve' => function ($listing, $args) {
return [
'items' => new CursorPaginator(
$listing?->bids,
$args['first'],
Arr::get($args, 'after') ? Cursor::fromEncoded($args['after']) : null,
['parameters' => ['id']]
),
'total' => (int) $listing?->bids_count,
];
},
'resolve' => fn ($listing, $args) => [
'items' => new CursorPaginator(
$listing?->bids,
$args['first'],
Arr::get($args, 'after') ? Cursor::fromEncoded($args['after']) : null,
['parameters' => ['id']]
),
'total' => (int) $listing?->bids_count,
],
],
'states' => [
'type' => GraphQL::type('[MarketplaceState!]'),
Expand Down
65 changes: 27 additions & 38 deletions src/Models/Laravel/Traits/EagerLoadSelectFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,30 @@ public static function selectFields(ResolveInfo $resolveInfo, string $query): ar
static::$query = $query;
$queryPlan = $resolveInfo->lookAhead()->queryPlan();

switch ($query) {
case 'GetListings':
case 'GetListing':
[$select, $with, $withCount] = static::loadListings(
$queryPlan,
$query == 'GetListings' ? 'edges.fields.node.fields' : '',
[],
null,
true
);

break;
case 'GetBids':
case 'GetBid':
[$select, $with, $withCount] = static::loadBids(
$queryPlan,
$query == 'GetBids' ? 'edges.fields.node.fields' : '',
[],
null,
true
);

break;
case 'GetSales':
case 'GetSale':
[$select, $with, $withCount] = static::loadSales(
$queryPlan,
$query == 'GetSales' ? 'edges.fields.node.fields' : '',
[],
null,
true
);

break;
}
[$select, $with, $withCount] = match ($query) {
'GetListings', 'GetListing' => static::loadListings(
$queryPlan,
$query == 'GetListings' ? 'edges.fields.node.fields' : '',
[],
null,
true
),
'GetBids', 'GetBid' => static::loadBids(
$queryPlan,
$query == 'GetBids' ? 'edges.fields.node.fields' : '',
[],
null,
true
),
'GetSales', 'GetSale' => static::loadSales(
$queryPlan,
$query == 'GetSales' ? 'edges.fields.node.fields' : '',
[],
null,
true
),
default => [$select, $with, $withCount],
};


return [$select, $with, $withCount];
Expand Down Expand Up @@ -97,7 +86,7 @@ public static function loadListings(

if (!$isParent) {
$with = [
$key => function ($query) use ($select, $args) {
$key => function ($query) use ($select, $args): void {
$query->select(array_unique($select))
->when($cursor = Cursor::fromEncoded(Arr::get($args, 'after')), fn ($q) => $q->where('id', '>', $cursor->parameter('id')))
->orderBy('marketplace_listings.id');
Expand Down Expand Up @@ -155,7 +144,7 @@ public static function loadBids(

if (!$isParent) {
$with = [
$key => function ($query) use ($select, $args) {
$key => function ($query) use ($select, $args): void {
$query->select(array_unique($select))
->when($cursor = Cursor::fromEncoded(Arr::get($args, 'after')), fn ($q) => $q->where('id', '>', $cursor->parameter('id')))
->orderBy('marketplace_bids.id');
Expand Down Expand Up @@ -206,7 +195,7 @@ public static function loadSales(

if (!$isParent) {
$with = [
$key => function ($query) use ($select, $args) {
$key => function ($query) use ($select, $args): void {
$query->select(array_unique($select))
->when($cursor = Cursor::fromEncoded(Arr::get($args, 'after')), fn ($q) => $q->where('id', '>', $cursor->parameter('id')))
->orderBy('marketplace_sales.id');
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/MinimumPrice.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
$listing?->highestBid?->price ?? $listing?->price,
1.05
);
if (bccomp($value, $price) < 0) {
if (bccomp((string) $value, $price) < 0) {
$fail('enjin-platform-marketplace::validation.minimum_price')->translate(['price' => $price]);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/Services/Processor/Substrate/Codec/Encoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Encoder extends BaseEncoder
{
protected static array $callIndexKeys = [
'CreateListing' => 'Marketplace.create_listing',
'CreateListingV1010' => 'Marketplace.create_listing',
'CancelListing' => 'Marketplace.cancel_listing',
'FillListing' => 'Marketplace.fill_listing',
'FinalizeAuction' => 'Marketplace.finalize_auction',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ abstract class MarketplaceSubstrateEvent extends SubstrateEvent
protected function getListing(string $listingId): Model
{
if (!$listing = MarketplaceListing::where(['listing_chain_id' => $listingId])->first()) {
throw new PlatformException(__('enjin-platform::traits.query_data_or_fail.unable_to_find_listing', ['class' => __CLASS__, 'listingId' => $listingId]));
throw new PlatformException(__('enjin-platform::traits.query_data_or_fail.unable_to_find_listing', ['class' => self::class, 'listingId' => $listingId]));
}

return $listing;
Expand Down
Loading
Loading