enjin/platform-core
Core Laravel package for the Enjin Platform, providing shared models, services, and GraphQL APIs for managing blockchain collections, tokens, wallets, and transactions on Enjin networks. Built to power modular NFT platform integrations.
This is a Laravel package — it is almost always consumed through the enjin/platform-laravel application shell rather than installed standalone. If you are building the API yourself:
composer require enjin/platform-core
php artisan vendor:publish --tag=platform-config
php artisan migrate
The service provider is auto-discovered (Enjin\Platform\CoreServiceProvider). Confirm it loaded with php artisan about and check that the platform database connection and migrations ran cleanly.
Where to look first, in order:
config/platform.php — network selection, encryption, queue names, batching, and the SDK endpoint all live here.src/GraphQL/Schemas and src/GraphQL/Types — this is the public contract. Everything a consumer can call is defined here.src/Services — the domain layer (CollectionService, TokenService, TransactionService, WalletService). This is where you extend behavior.src/Models — Collection, Token, Wallet, Transaction, Balance. Eloquent models mirror the on-chain entities.src/Commands — artisan commands for syncing state and managing accounts.First use case: boot the app, point it at a testnet (or the local dev node), then query the GraphQL endpoint. A minimal ListCollections query returning id, collectionId, name will confirm the schema, DB, and node connection are all healthy in one shot. If you only need read access from PHP, you can skip GraphQL entirely and query Collection::find($id) directly.
GraphQL as the boundary, services as the core. Mutations should be thin — validate, dispatch, return a payload. Anything with business logic belongs in a Service class so it can be unit-tested without HTTP. Follow the existing pattern of one service per aggregate.
Transactions go through the queue. On-chain writes (minting, transfers, collection creation) are queued Transaction records that a worker signs and submits. Never assume a mutation implies the chain write has happened — return the transaction ID and let the client poll GetTransaction or listen for the completed event. Keep a long-running queue worker in development (php artisan queue:work --queue=transactions) or you will debug "nothing happens" for an hour.
Use the data objects, not raw arrays. The package ships laravel-data DTOs under src/Data. Accept them in mutation resolvers and services rather than arrays — you get validation and IDE help for free.
Extend by adding, not editing. The intended extension points are: a new Type + Mutation for the schema, a new Service for logic, a new Event/Listener pair if you need to react to chain state. Avoid modifying vendor files; register your own provider and point Lighthouse at an extended schema.
Sync commands are your reconcile tool. Scheduled platform:sync-collection / token sync jobs keep local state truthful when events were missed (worker downtime, reorgs). Wire them into your scheduler and run them manually after any incident.
Testing. Use RefreshDatabase against a SQLite in-memory connection for the happy path, but stub the SDK client for anything that would hit a node. Fake queued transactions with Queue::fake() and assert on the dispatched job payload — that is the fastest way to verify your mutation without a chain.
amount, cast to string and use brick/math or GMP. A float cast will silently corrupt balances.php artisan lighthouse:clear-cache. Changes that "don't appear" are almost always stale cache, not a bug.composer update. Diff it against the vendor copy after every version bump or new keys will be missing with confusing defaults.APP_KEY without re-encrypting makes wallets unrecoverable. Back up the database and the key together.sync works for smoke tests but will block HTTP requests for tens of seconds on real transactions. Always use Redis or a database queue behind a dedicated worker.Transaction and Balance update local state. Bulk updates that bypass events (->update() on a query builder) will leave the database inconsistent — use model instances or explicitly fire the observer logic.canary config against a mainnet node may not error immediately; you get empty results instead. Log the resolved network and endpoint at boot and check it whenever data looks wrong.transactions table first (state, error, transaction_chain_id), then the worker log. Most failures are signing (bad key/account), insufficient balance for fees, or a nonce collision from parallel workers — serialize per-wallet if you see collisions.How can I help you explore Laravel packages today?