├── .github └── workflows │ └── nodejs.yml.disabled ├── .gitignore ├── .husky └── pre-push ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .verdaccio └── config.yml ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── aiken.lock ├── documentation ├── README.md ├── game-design-considerations.md ├── implementing-a-game-state-machine.md ├── modules.png ├── paima-assertions.md └── paimaSM.md ├── eslint.config.js ├── nx.json ├── package-lock.json ├── package.json ├── packages ├── admin-panel │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── ControlPanel.tsx │ │ ├── InfoPanel.tsx │ │ ├── ethereum.ts │ │ ├── favicon.svg │ │ ├── hooks │ │ │ └── useInterval.ts │ │ ├── index.css │ │ ├── main.tsx │ │ ├── tx-template.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── batcher │ ├── .env.localhost │ ├── .gitignore │ ├── README.md │ ├── address-validator │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── date-utils.ts │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── batcher-standalone │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── esbuildconfig.cjs │ │ ├── package.json │ │ ├── scripts │ │ │ ├── docker │ │ │ │ ├── Dockerfile │ │ │ │ ├── docker-compose.yml │ │ │ │ ├── shutdown.sh │ │ │ │ └── start.sh │ │ │ └── post_build.sh │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── batcher-transaction-poster │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── avail.ts │ │ │ ├── evm.ts │ │ │ ├── gas-limit.ts │ │ │ ├── index.ts │ │ │ └── transactionPoster.ts │ │ └── tsconfig.json │ ├── db │ │ ├── .gitignore │ │ ├── README.md │ │ ├── migrations │ │ │ ├── down.sql │ │ │ └── up.sql │ │ ├── package.json │ │ ├── pgtypedconfig.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── sql │ │ │ │ ├── queries.queries.ts │ │ │ │ └── queries.sql │ │ └── tsconfig.json │ ├── game-input-validator │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── default-validator.ts │ │ │ ├── empty-validator.ts │ │ │ ├── errors.ts │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── runtime │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── pg │ │ │ │ └── pgPool.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── tsconfig.json │ ├── utils │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── config-validation.ts │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── version.ts │ │ └── tsconfig.json │ └── webserver │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ ├── index.ts │ │ └── recaptcha.ts │ │ └── tsconfig.json ├── build-utils │ ├── paima-build-utils │ │ ├── README.md │ │ ├── package.json │ │ ├── scripts │ │ │ ├── change-db.js │ │ │ ├── copyAssets.cjs │ │ │ └── esbuild.sh │ │ ├── src │ │ │ ├── middleware-esbuildconfig.template.cts │ │ │ ├── middleware-esbuildconfig.template.mts │ │ │ ├── standalone-esbuildconfig.template.cts │ │ │ └── standalone-esbuildconfig.template.mts │ │ ├── tsconfig.base.json │ │ ├── tsconfig.cjs.json │ │ ├── tsconfig.esm.json │ │ └── tsconfig.json │ ├── paima-plugin-viem │ │ └── src │ │ │ └── index.ts │ └── tsconfig.json ├── cardano-contracts │ ├── aiken-mdx │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── components │ │ │ │ ├── aiken │ │ │ │ │ ├── AikenBaseType.tsx │ │ │ │ │ ├── AikenConstructorMap.tsx │ │ │ │ │ ├── AikenConstructorMapField.tsx │ │ │ │ │ ├── AikenConstructorSimple.tsx │ │ │ │ │ ├── AikenConstructorTuple.tsx │ │ │ │ │ ├── AikenDatum.tsx │ │ │ │ │ ├── AikenDefinitionBlock.tsx │ │ │ │ │ ├── AikenDefinitions.tsx │ │ │ │ │ ├── AikenEnum.tsx │ │ │ │ │ ├── AikenListType.tsx │ │ │ │ │ ├── AikenMapType.tsx │ │ │ │ │ ├── AikenParameter.tsx │ │ │ │ │ ├── AikenProject.tsx │ │ │ │ │ ├── AikenRedeemer.tsx │ │ │ │ │ ├── AikenTupleType.tsx │ │ │ │ │ ├── AikenValidator.tsx │ │ │ │ │ ├── AikenValidators.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils │ │ │ │ │ ├── CommentBlock.tsx │ │ │ │ │ ├── HeaderWrapper.tsx │ │ │ │ │ ├── OutlineBlock.tsx │ │ │ │ │ └── index.ts │ │ │ ├── context │ │ │ │ ├── AnchorProvider.tsx │ │ │ │ ├── IsLocalProvider.tsx │ │ │ │ ├── TypesProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── render.mts │ │ │ └── templates │ │ │ │ ├── plutus.hbs │ │ │ │ └── prelude.hbs │ │ ├── test │ │ │ ├── .gitignore │ │ │ ├── aiken-mdx-test │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── aiken.lock │ │ │ │ ├── aiken.toml │ │ │ │ ├── lib │ │ │ │ │ └── aiken-mdx-test │ │ │ │ │ │ ├── utils.ak │ │ │ │ │ │ └── validation.ak │ │ │ │ ├── plutus.json │ │ │ │ └── validators │ │ │ │ │ └── whirl.ak │ │ │ └── multiple.hbs │ │ └── tsconfig.json │ └── inverse-whirlpool │ │ ├── .gitignore │ │ ├── README.md │ │ ├── aiken.toml │ │ ├── lib │ │ └── inverse_whirlpool │ │ │ ├── conversion.ak │ │ │ ├── tests │ │ │ └── unit │ │ │ │ └── conversions.ak │ │ │ ├── types │ │ │ ├── actions.ak │ │ │ └── data.ak │ │ │ ├── utils.ak │ │ │ └── validation.ak │ │ ├── package.json │ │ ├── src │ │ ├── actions.js │ │ ├── contract.js │ │ ├── main.js │ │ ├── package.json │ │ └── util.js │ │ └── validators │ │ ├── true.ak │ │ └── whirl.ak ├── contracts │ └── evm-contracts │ │ ├── .gitignore │ │ ├── README.md │ │ ├── contracts │ │ ├── AnnotatedMintNft.sol │ │ ├── BaseState.sol │ │ ├── ERC1967.sol │ │ ├── Erc20NftSale.sol │ │ ├── GenericPayment.sol │ │ ├── NativeNftSale.sol │ │ ├── PaimaL2Contract.sol │ │ ├── Proxy │ │ │ ├── Erc20NftSaleProxy.sol │ │ │ ├── GenericPaymentProxy.sol │ │ │ ├── NativeNftSaleProxy.sol │ │ │ └── OrderbookDexProxy.sol │ │ ├── README.md │ │ ├── State.sol │ │ ├── dev │ │ │ ├── ERC721Dev.sol │ │ │ ├── Erc20Dev.sol │ │ │ ├── NativeNftSaleUpgradeDev.sol │ │ │ ├── NftSaleUpgradeDev.sol │ │ │ ├── NftTypeMapper.sol │ │ │ ├── Token.sol │ │ │ └── UpgradeDev.sol │ │ ├── orderbook │ │ │ ├── IOrderbookDex.sol │ │ │ └── OrderbookDex.sol │ │ └── token │ │ │ ├── IERC4906Agnostic.sol │ │ │ ├── IInverseAppProjected1155.sol │ │ │ ├── IInverseAppProjectedNft.sol │ │ │ ├── IInverseBaseProjected1155.sol │ │ │ ├── IInverseBaseProjectedNft.sol │ │ │ ├── IInverseProjected1155.sol │ │ │ ├── IInverseProjectedNft.sol │ │ │ ├── ITokenUri.sol │ │ │ ├── IUri.sol │ │ │ ├── InverseAppProjected1155.sol │ │ │ ├── InverseAppProjectedNft.sol │ │ │ ├── InverseBaseProjected1155.sol │ │ │ └── InverseBaseProjectedNft.sol │ │ ├── docs │ │ └── templates │ │ │ ├── contract.hbs │ │ │ ├── helpers.js │ │ │ ├── page.hbs │ │ │ └── properties.js │ │ ├── foundry.toml │ │ ├── hardhat.config.ts │ │ ├── package.json │ │ ├── prepare.sh │ │ ├── src │ │ ├── common.ts │ │ ├── deployment.ts │ │ ├── index.ts │ │ ├── paimaL2.ts │ │ └── recommendedHardhat.ts │ │ ├── test-lib │ │ ├── StdInvariant.sol │ │ ├── cheatcodes.sol │ │ ├── console.sol │ │ └── ctest.sol │ │ ├── test │ │ ├── InverseAppProjected1155.t.sol │ │ ├── InverseAppProjectedNft.t.sol │ │ ├── InverseBaseProjected1155.t.sol │ │ ├── InverseBaseProjectedNft.t.sol │ │ ├── OrderbookDex.t.sol │ │ ├── OrderbookDexInvariant.t.sol │ │ └── PaimaL2ContractTest.sol │ │ └── tsconfig.json ├── engine │ └── tsconfig.json ├── node-sdk │ ├── paima-broker │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── event-broker.ts │ │ │ └── index.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── paima-db │ │ ├── README.md │ │ ├── docker-compose.yml │ │ ├── docker-postgres.sh │ │ ├── migrations │ │ │ ├── down.sql │ │ │ └── up.sql │ │ ├── package.json │ │ ├── pgtypedconfig.json │ │ ├── src │ │ │ ├── data-migrations.ts │ │ │ ├── database-validation.ts │ │ │ ├── delegate-wallet.ts │ │ │ ├── event-indexing.ts │ │ │ ├── index.ts │ │ │ ├── paima-tables.ts │ │ │ ├── pg-connection.ts │ │ │ ├── pg-tx.ts │ │ │ ├── postgres-metadata.ts │ │ │ ├── register-events.ts │ │ │ ├── scheduled-constructors.ts │ │ │ ├── sql │ │ │ │ ├── achievements.queries.ts │ │ │ │ ├── achievements.sql │ │ │ │ ├── block-heights.queries.ts │ │ │ │ ├── block-heights.sql │ │ │ │ ├── cardano-last-epoch.queries.ts │ │ │ │ ├── cardano-last-epoch.sql │ │ │ │ ├── cde-cardano-asset-utxos.queries.ts │ │ │ │ ├── cde-cardano-asset-utxos.sql │ │ │ │ ├── cde-cardano-mint-burn.queries.ts │ │ │ │ ├── cde-cardano-mint-burn.sql │ │ │ │ ├── cde-cardano-pool-delegation.queries.ts │ │ │ │ ├── cde-cardano-pool-delegation.sql │ │ │ │ ├── cde-cardano-projected-nft.queries.ts │ │ │ │ ├── cde-cardano-projected-nft.sql │ │ │ │ ├── cde-cardano-transfer.queries.ts │ │ │ │ ├── cde-cardano-transfer.sql │ │ │ │ ├── cde-cursor-tracking-pagination.queries.ts │ │ │ │ ├── cde-cursor-tracking-pagination.sql │ │ │ │ ├── cde-erc1155.queries.ts │ │ │ │ ├── cde-erc1155.sql │ │ │ │ ├── cde-erc20-deposit.queries.ts │ │ │ │ ├── cde-erc20-deposit.sql │ │ │ │ ├── cde-erc20.queries.ts │ │ │ │ ├── cde-erc20.sql │ │ │ │ ├── cde-erc6551-registry.queries.ts │ │ │ │ ├── cde-erc6551-registry.sql │ │ │ │ ├── cde-erc721.queries.ts │ │ │ │ ├── cde-erc721.sql │ │ │ │ ├── cde-generic.queries.ts │ │ │ │ ├── cde-generic.sql │ │ │ │ ├── cde-tracking.queries.ts │ │ │ │ ├── cde-tracking.sql │ │ │ │ ├── dynamic-primitives.queries.ts │ │ │ │ ├── dynamic-primitives.sql │ │ │ │ ├── emulated.queries.ts │ │ │ │ ├── emulated.sql │ │ │ │ ├── events.queries.ts │ │ │ │ ├── events.sql │ │ │ │ ├── extensions.queries.ts │ │ │ │ ├── extensions.sql │ │ │ │ ├── midnight-funnel.queries.ts │ │ │ │ ├── midnight-funnel.sql │ │ │ │ ├── mina-checkpoints.queries.ts │ │ │ │ ├── mina-checkpoints.sql │ │ │ │ ├── nonces.queries.ts │ │ │ │ ├── nonces.sql │ │ │ │ ├── rollup_inputs.queries.ts │ │ │ │ ├── rollup_inputs.sql │ │ │ │ ├── statistics.queries.ts │ │ │ │ ├── statistics.sql │ │ │ │ ├── wallet-delegation.queries.ts │ │ │ │ └── wallet-delegation.sql │ │ │ ├── table-types.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── paima-engine │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── paima-funnel │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── cde │ │ │ │ ├── cardanoMintBurn.ts │ │ │ │ ├── cardanoPool.ts │ │ │ │ ├── cardanoProjectedNFT.ts │ │ │ │ ├── cardanoTransfer.ts │ │ │ │ ├── delayedAsset.ts │ │ │ │ ├── dynamic.ts │ │ │ │ ├── erc1155.ts │ │ │ │ ├── erc20.ts │ │ │ │ ├── erc20Deposit.ts │ │ │ │ ├── erc6551Registry.ts │ │ │ │ ├── erc721.ts │ │ │ │ ├── generic.ts │ │ │ │ ├── minaGeneric.ts │ │ │ │ ├── paimaErc721.ts │ │ │ │ └── reading.ts │ │ │ ├── funnels │ │ │ │ ├── BaseFunnel.ts │ │ │ │ ├── FunnelCache.ts │ │ │ │ ├── avail │ │ │ │ │ ├── baseFunnel.ts │ │ │ │ │ ├── cache.ts │ │ │ │ │ ├── createApi.ts │ │ │ │ │ ├── parallelFunnel.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── block │ │ │ │ │ └── funnel.ts │ │ │ │ ├── carp │ │ │ │ │ └── funnel.ts │ │ │ │ ├── emulated │ │ │ │ │ ├── funnel.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── midnight │ │ │ │ │ └── funnel.ts │ │ │ │ ├── mina │ │ │ │ │ └── funnel.ts │ │ │ │ └── parallelEvm │ │ │ │ │ └── funnel.ts │ │ │ ├── index.ts │ │ │ ├── paima-l2-processing.ts │ │ │ ├── reading.ts │ │ │ └── utils.ts │ │ └── tsconfig.json │ ├── paima-rest │ │ ├── package.json │ │ ├── src │ │ │ ├── EngineService.ts │ │ │ ├── controllers │ │ │ │ ├── AchievementsController.ts │ │ │ │ └── BasicControllers.ts │ │ │ ├── index.ts │ │ │ └── tsoa │ │ │ │ ├── routes.ts │ │ │ │ └── swagger.json │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── tsoa.json │ ├── paima-runtime │ │ ├── .gitignore │ │ ├── package.json │ │ ├── public │ │ │ └── asyncapi.html │ │ ├── src │ │ │ ├── cde-config │ │ │ │ ├── loading.ts │ │ │ │ ├── utils.ts │ │ │ │ └── validation.ts │ │ │ ├── evm-rpc │ │ │ │ ├── cache.ts │ │ │ │ ├── eip1193.ts │ │ │ │ ├── mock.ts │ │ │ │ ├── types.ts │ │ │ │ └── validate.ts │ │ │ ├── index.ts │ │ │ ├── nonce-gc.ts │ │ │ ├── run-flag.ts │ │ │ ├── runtime-loops.ts │ │ │ ├── server.ts │ │ │ ├── snapshots.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── test │ │ │ ├── config.test.ts │ │ │ └── example.yml │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── paima-sm │ │ ├── .gitignore │ │ ├── package.json │ │ ├── src │ │ │ ├── cde-cardano-delayed-asset.ts │ │ │ ├── cde-cardano-mint-burn.ts │ │ │ ├── cde-cardano-pool.ts │ │ │ ├── cde-cardano-projected-nft.ts │ │ │ ├── cde-cardano-transfer.ts │ │ │ ├── cde-erc1155-transfer.ts │ │ │ ├── cde-erc20-deposit.ts │ │ │ ├── cde-erc20-transfer.ts │ │ │ ├── cde-erc6551-registry.ts │ │ │ ├── cde-erc721-mint.ts │ │ │ ├── cde-erc721-transfer.ts │ │ │ ├── cde-evm-dynamic-primitive.ts │ │ │ ├── cde-generic.ts │ │ │ ├── cde-midnight-contract-state.ts │ │ │ ├── cde-processing.ts │ │ │ ├── delegate-wallet.ts │ │ │ ├── index.ts │ │ │ ├── randomness.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── paima-utils-backend │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── achievements.ts │ │ │ ├── cde-access-internals.ts │ │ │ ├── cde-access.ts │ │ │ ├── index.ts │ │ │ ├── security.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── publish-wrapper │ │ ├── README.md │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ │ ├── broker.ts │ │ │ ├── db.ts │ │ │ ├── engine.ts │ │ │ └── utils-backend.ts │ │ └── tsconfig.json │ └── tsconfig.json └── paima-sdk │ ├── paima-chain-types │ ├── package.json │ ├── src │ │ ├── hash.ts │ │ ├── index.ts │ │ └── types.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-concise │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── PaimaParser.ts │ │ ├── batcher.ts │ │ ├── builder.ts │ │ ├── consumer.ts │ │ ├── index.ts │ │ ├── types.ts │ │ ├── utils.ts │ │ └── v1 │ │ │ ├── builder.ts │ │ │ ├── consts.ts │ │ │ └── utils.ts │ ├── test │ │ ├── paima-parser.array-optional.test.ts │ │ ├── paima-parser.at-user.test.ts │ │ ├── paima-parser.base64.test.ts │ │ ├── paima-parser.chess.test.ts │ │ ├── paima-parser.optional.test.ts │ │ ├── paima-parser.single.test.ts │ │ └── paima-parser.test.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-config │ ├── package.json │ ├── src │ │ ├── ConfigBuilder.ts │ │ ├── configCheck.ts │ │ ├── index.ts │ │ └── schema │ │ │ ├── funnel │ │ │ ├── evm.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ ├── network │ │ │ ├── evm.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ │ ├── primitive │ │ │ ├── evm.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ │ └── utils.ts │ ├── test │ │ └── config.spec.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-crypto │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── IVerify.ts │ │ ├── algorand.ts │ │ ├── cardano.ts │ │ ├── evm.ts │ │ ├── index.ts │ │ ├── mina.ts │ │ └── polkadot.ts │ ├── test │ │ └── index.test.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-events │ ├── README.md │ ├── package.json │ ├── src │ │ ├── app-events.ts │ │ ├── asyncapi.ts │ │ ├── builtin-event-utils.ts │ │ ├── builtin-events.ts │ │ ├── event-connect.ts │ │ ├── event-manager.ts │ │ ├── evm.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── test │ │ ├── builtin.yml │ │ ├── hashed.yml │ │ └── index.test.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-executors │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── match_executor.ts │ │ ├── round_executor.ts │ │ └── types.ts │ └── tsconfig.json │ ├── paima-mw-core │ ├── README.md │ ├── esbuildconfig.cjs │ ├── package.json │ ├── src │ │ ├── delegate-wallet │ │ │ └── index.ts │ │ ├── endpoints │ │ │ ├── accounts.ts │ │ │ ├── internal.ts │ │ │ ├── queries.ts │ │ │ └── utility.ts │ │ ├── errors.ts │ │ ├── global.d.ts │ │ ├── helpers │ │ │ ├── auxiliary-queries.ts │ │ │ ├── clients.ts │ │ │ ├── data-processing.ts │ │ │ ├── general.ts │ │ │ ├── logging.ts │ │ │ ├── paima-node-rest-schema.d.ts │ │ │ ├── posting.ts │ │ │ ├── query-constructors.ts │ │ │ └── transaction-building.ts │ │ ├── index.ts │ │ ├── name-generation │ │ │ ├── adjectives.ts │ │ │ ├── index.ts │ │ │ └── nouns.ts │ │ ├── state.ts │ │ ├── types.ts │ │ └── wallets │ │ │ ├── algorand.ts │ │ │ ├── avail.ts │ │ │ ├── cardano.ts │ │ │ ├── evm │ │ │ ├── ethers.ts │ │ │ └── injected.ts │ │ │ ├── mina.ts │ │ │ ├── polkadot.ts │ │ │ ├── wallet-modes.ts │ │ │ └── wallets.ts │ ├── tsconfig.json │ └── web │ │ ├── .gitignore │ │ ├── TemplateData │ │ ├── bg-green-oval-up.png │ │ ├── bg-green-oval-up.png.meta │ │ ├── catapult_background.png │ │ ├── catapult_background.png.meta │ │ ├── favicon.ico │ │ ├── favicon.ico.meta │ │ ├── fullscreen.svg │ │ ├── fullscreen.svg.meta │ │ ├── paima-loading.gif │ │ ├── paima-loading.gif.meta │ │ ├── paima-logo.svg │ │ ├── paima-logo.svg.meta │ │ ├── progress-bar-empty.png │ │ ├── progress-bar-empty.png.meta │ │ ├── progress-bar-full.png │ │ ├── progress-bar-full.png.meta │ │ ├── style.css │ │ └── tailwind.css │ │ └── index.html │ ├── paima-prando │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json │ ├── paima-precompiles │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-providers │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── IProvider.ts │ │ ├── algorand.ts │ │ ├── avail.ts │ │ ├── cardano.ts │ │ ├── errors.ts │ │ ├── evm │ │ │ ├── ethers.ts │ │ │ ├── index.ts │ │ │ ├── injected.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── mina.ts │ │ ├── polkadot.ts │ │ ├── utils.ts │ │ └── window.ts │ ├── test │ │ └── index.test.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ ├── paima-sdk │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── chain-types.ts │ │ ├── concise.ts │ │ ├── config.ts │ │ ├── crypto.ts │ │ ├── events.ts │ │ ├── executors.ts │ │ ├── mw-core.ts │ │ ├── prando.ts │ │ ├── precompiles.ts │ │ ├── providers.ts │ │ └── utils.ts │ └── tsconfig.json │ ├── paima-utils │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── artifacts │ │ │ ├── ERC165Contract.json │ │ │ ├── ERC165Contract.ts │ │ │ ├── ERC20Contract.json │ │ │ ├── ERC20Contract.ts │ │ │ ├── ERC6551RegistryContract.json │ │ │ ├── ERC6551RegistryContract.ts │ │ │ ├── ERC721Contract.json │ │ │ ├── ERC721Contract.ts │ │ │ ├── IERC1155Contract.json │ │ │ ├── IERC1155Contract.ts │ │ │ ├── OldERC6551RegistryContract.json │ │ │ ├── OldERC6551RegistryContract.ts │ │ │ ├── PaimaERC721Contract.json │ │ │ ├── PaimaERC721Contract.ts │ │ │ ├── PaimaL2Contract.json │ │ │ └── PaimaL2Contract.ts │ │ ├── captcha.ts │ │ ├── config.ts │ │ ├── config │ │ │ ├── loading.ts │ │ │ └── singleton.ts │ │ ├── constants.ts │ │ ├── contracts.ts │ │ ├── index.ts │ │ ├── logging.ts │ │ ├── security │ │ │ └── parse.ts │ │ └── types │ │ │ ├── index.ts │ │ │ ├── json-query.ts │ │ │ └── misc.ts │ ├── test │ │ └── security │ │ │ ├── config.yml │ │ │ └── index.test.ts │ ├── tsconfig.build.json │ └── tsconfig.json │ └── tsconfig.json ├── project.json ├── tools └── scripts │ ├── bump-version.sh │ ├── check-implicit-dependencies.ts │ ├── publish-local.mts │ └── unpack.sh ├── tsconfig.base.json └── wipe.sh /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bin 3 | .nx 4 | **/dist 5 | **/build 6 | **/*.tsbuildinfo 7 | 8 | # logs 9 | *.log 10 | 11 | .idea/ -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | npm run cilint 2 | npm run test 3 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/iron -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.queries.ts 2 | **/*.d.ts 3 | contract-types/ 4 | packaged/ 5 | packages/engine/paima-rest/src/tsoa/routes.ts 6 | packages/contracts/evm-contracts/test-lib 7 | packages/contracts/evm-contracts/typechain-types 8 | **/dist 9 | **/build 10 | bin/ 11 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "arrowParens": "avoid", 8 | "plugins": ["prettier-plugin-solidity"], 9 | "overrides": [ 10 | { 11 | "files": "*.sol", 12 | "options": { 13 | "tabWidth": 4, 14 | "singleQuote": false, 15 | "arrowParens": "avoid", 16 | "parser": "solidity-parse" 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /.verdaccio/config.yml: -------------------------------------------------------------------------------- 1 | # path to a directory with all packages 2 | storage: ../build/local-registry/storage 3 | 4 | auth: 5 | htpasswd: 6 | file: ./htpasswd 7 | 8 | # a list of other known repositories we can talk to 9 | uplinks: 10 | npmjs: 11 | url: https://registry.npmjs.org/ 12 | maxage: 60m 13 | max_fails: 20 14 | fail_timeout: 2m 15 | yarn: 16 | url: https://registry.yarnpkg.com 17 | maxage: 60m 18 | max_fails: 20 19 | fail_timeout: 2m 20 | 21 | packages: 22 | # for @paima packages, we never want to fallback to the npm registry 23 | # otherwise, the local version will get rejected because the npm registry has a package with the same version 24 | '@paima/*': 25 | # allow all users full access (since it's a local registry) 26 | access: $all 27 | publish: $all 28 | unpublish: $all 29 | 30 | '**': 31 | access: $all 32 | publish: $all 33 | unpublish: $all 34 | proxy: npmjs # fallback to npmjs for non-paima package. This is needed for transitive dependencies to work 35 | 36 | # log settings 37 | log: 38 | type: stdout 39 | format: pretty 40 | level: warn 41 | 42 | publish: 43 | allow_offline: true # set offline to true to allow publish offline 44 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.formatOnSave": true, 4 | "[typescript]": { 5 | "editor.defaultFormatter": "esbenp.prettier-vscode" 6 | }, 7 | "[typescriptreact]": { 8 | "editor.defaultFormatter": "esbenp.prettier-vscode" 9 | }, 10 | "[solidity]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode" 12 | }, 13 | "files.associations": { 14 | ".env.*": "properties" 15 | }, 16 | "[sql]": { 17 | "editor.formatOnSave": false 18 | }, 19 | "[json][jsonc][json5]": { 20 | "editor.formatOnSave": true 21 | }, 22 | "eslint.experimental.useFlatConfig": true, 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Paima Studios 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /aiken.lock: -------------------------------------------------------------------------------- 1 | # This file was generated by Aiken 2 | # You typically do not need to edit this file 3 | 4 | [[requirements]] 5 | name = "aiken-lang/stdlib" 6 | version = "1.9.0" 7 | source = "github" 8 | 9 | [[requirements]] 10 | name = "aiken-lang/fuzz" 11 | version = "main" 12 | source = "github" 13 | 14 | [[requirements]] 15 | name = "aiken-lang/sparse-merkle-tree" 16 | version = "main" 17 | source = "github" 18 | 19 | [[packages]] 20 | name = "aiken-lang/stdlib" 21 | version = "1.9.0" 22 | requirements = [] 23 | source = "github" 24 | 25 | [[packages]] 26 | name = "aiken-lang/fuzz" 27 | version = "main" 28 | requirements = [] 29 | source = "github" 30 | 31 | [[packages]] 32 | name = "aiken-lang/sparse-merkle-tree" 33 | version = "main" 34 | requirements = [] 35 | source = "github" 36 | 37 | [etags] 38 | "aiken-lang/fuzz@main" = [{ secs_since_epoch = 1720184431, nanos_since_epoch = 623504751 }, "a8294651f1577c671d580c99c9bc5445ef1fd44e4aa3dde550434a4cbc8d50b6"] 39 | "aiken-lang/sparse-merkle-tree@main" = [{ secs_since_epoch = 1720184432, nanos_since_epoch = 277332931 }, "076db86c829f1bf2be5e996c9c1a714efcb761452d8abb8ae2b311e95c4aa6ed"] 40 | -------------------------------------------------------------------------------- /documentation/README.md: -------------------------------------------------------------------------------- 1 | # Deprecated docs 2 | 3 | The docs here are deprecated and meant to be slowly replaced by [the new docs](https://docs.paimastudios.com) 4 | -------------------------------------------------------------------------------- /documentation/modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/documentation/modules.png -------------------------------------------------------------------------------- /packages/admin-panel/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /packages/admin-panel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/admin-panel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paima-contract-admin-panel", 3 | "private": true, 4 | "version": "1.0.0", 5 | "scripts": { 6 | "lint:eslint": "eslint .", 7 | "dev": "vite", 8 | "host": "vite --host 3001", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@esbuild-plugins/node-globals-polyfill": "^0.2.3", 14 | "@esbuild-plugins/node-modules-polyfill": "^0.2.2", 15 | "@metamask/providers": "^10.2.1", 16 | "react": "^18.0.0", 17 | "react-dom": "^18.0.0", 18 | "rollup-plugin-node-polyfills": "^0.2.1" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.0.0", 22 | "@types/react-dom": "^18.0.0", 23 | "@vitejs/plugin-react": "^1.3.0", 24 | "typescript": "^5.5.3", 25 | "vite": "^2.9.9" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/admin-panel/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | } 3 | 4 | .App-logo { 5 | height: 40vmin; 6 | pointer-events: none; 7 | } 8 | 9 | @media (prefers-reduced-motion: no-preference) { 10 | .App-logo { 11 | animation: App-logo-spin infinite 20s linear; 12 | } 13 | } 14 | 15 | .App-header { 16 | background-color: #282c34; 17 | min-height: 10vh; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | font-size: calc(10px + 2vmin); 23 | color: white; 24 | text-align: center; 25 | } 26 | 27 | .App-body { 28 | background-color: #282c34; 29 | min-height: 10vh; 30 | display: flex; 31 | flex-direction: column; 32 | align-items: left; 33 | justify-content: left; 34 | font-size: calc(10px + 1vmin); 35 | color: white; 36 | text-align: left; 37 | } 38 | 39 | .App-link { 40 | color: #61dafb; 41 | } 42 | 43 | @keyframes App-logo-spin { 44 | from { 45 | transform: rotate(0deg); 46 | } 47 | to { 48 | transform: rotate(360deg); 49 | } 50 | } 51 | 52 | button { 53 | font-size: calc(10px + 2vmin); 54 | } 55 | -------------------------------------------------------------------------------- /packages/admin-panel/src/ControlPanel.tsx: -------------------------------------------------------------------------------- 1 | interface Props { 2 | userAddress: string; 3 | inputString: string; 4 | setInputString: (s: string) => void; 5 | withdrawFundsFxn: () => void; 6 | connectWalletFxn: () => void; 7 | setFeeFxn: () => void; 8 | setOwnerFxn: () => void; 9 | } 10 | 11 | const ControlPanel = (props: Props) => { 12 | return ( 13 |
14 |

15 | Input: 16 | props.setInputString(e.currentTarget.value)} 20 | /> 21 |

22 |
23 | 24 | 25 | 26 | 27 |
28 |
29 | ); 30 | }; 31 | 32 | export default ControlPanel; 33 | -------------------------------------------------------------------------------- /packages/admin-panel/src/hooks/useInterval.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | const useInterval = (callback: () => void, delay: number | null) => { 4 | const savedCallback = useRef(callback); 5 | 6 | useEffect(() => { 7 | savedCallback.current = callback; 8 | }, [callback]); 9 | 10 | useEffect(() => { 11 | if (!delay && delay !== 0) { 12 | return; 13 | } 14 | const id = setInterval(() => savedCallback.current(), delay); 15 | return () => clearInterval(id); 16 | }, [delay]); 17 | }; 18 | 19 | export default useInterval; 20 | -------------------------------------------------------------------------------- /packages/admin-panel/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/admin-panel/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import App from './App'; 4 | import './index.css'; 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /packages/admin-panel/src/tx-template.ts: -------------------------------------------------------------------------------- 1 | import web3 from 'web3-utils'; 2 | const { numberToHex } = web3; 3 | 4 | import { 5 | DEFAULT_GAS_PRICE, 6 | getPaimaL2Contract, 7 | validatePaimaL2ContractAddress, 8 | } from '@paima/utils'; 9 | import type { PaimaL2Contract } from '@paima/utils'; 10 | import type { TransactionTemplate } from '@paima/utils'; 11 | 12 | export function getTxTemplate( 13 | storageAddress: string, 14 | methodName: T, 15 | ...data: Parameters 16 | ): TransactionTemplate { 17 | validatePaimaL2ContractAddress(storageAddress); 18 | const storage = getPaimaL2Contract(storageAddress); 19 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-assertion 20 | const txData = (storage.methods[methodName] as any)(...data).encodeABI(); 21 | return { 22 | data: txData, 23 | to: storageAddress, 24 | gasPrice: numberToHex(DEFAULT_GAS_PRICE), 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/admin-panel/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/admin-panel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /packages/admin-panel/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/batcher/.env.localhost: -------------------------------------------------------------------------------- 1 | # DB connection: 2 | BATCHER_DB_HOST="paima-batcher-db" 3 | BATCHER_DB_USER="postgres" 4 | BATCHER_DB_PW="postgres" 5 | BATCHER_DB_NAME="postgres" 6 | BATCHER_DB_PORT="5532" 7 | 8 | # Contract: 9 | CHAIN_URI="http://localhost:8545" 10 | CONTRACT_ADDRESS="0x5FbDB2315678afecb367f032d93F642f64180aa3" 11 | DEFAULT_FEE="10000000000000000" 12 | 13 | # Used to calculate the max gas spent on submitting a batch as an ax+b formula 14 | # Modify this to match the gas limits that work for the chain you're deploying to 15 | MAX_GAS_PER_BYTE="32" # ax where x = number of bytes 16 | MAX_BASE_GAS="50000" # b 17 | 18 | # Webserver: 19 | BATCHER_PORT="3340" 20 | 21 | # Validation parameters: 22 | GAME_NODE_URI= 23 | DEFAULT_VALIDATION_ACTIVE="false" 24 | GAME_INPUT_VALIDATOR_PERIOD="100" 25 | BATCHED_TRANSACTION_POSTER_PERIOD="100" 26 | BATCHED_MESSAGE_SIZE_LIMIT="100000" 27 | MAX_USER_INPUTS_PER_MINUTE="10" 28 | MAX_USER_INPUTS_PER_DAY="500" 29 | 30 | # Batcher wallet 31 | BATCHER_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" # hardhat local node key 32 | 33 | # Self-signing: 34 | SELF_SIGNING_ENABLED="false" 35 | SELF_SIGNING_API_KEY= 36 | -------------------------------------------------------------------------------- /packages/batcher/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.tsbuildinfo 3 | **/build 4 | *.log 5 | 6 | .env 7 | .env.production 8 | .env.development 9 | -------------------------------------------------------------------------------- /packages/batcher/README.md: -------------------------------------------------------------------------------- 1 | # Paima Batcher 2 | 3 | Paima Batcher is the first key component of the Paima Whirlpool infrastructure which enables cross-chain play (via account abstraction layer), paying transaction fees for users automatically, and decreasing overall fees by batching many game inputs together. 4 | 5 | ## Usage 6 | 7 | See the [Paima docs](https://docs.paimastudios.com) for usage 8 | 9 | ## [DEV] Usage without Docker 10 | 11 | You can also run the batcher without using docker, but for this, you will need an instance of postgres running with a database initialized using [`db/migrations/up.sql`](db/migrations/up.sql) and with its credentials specified in `.env.development`. Note also that in such a case, the batcher expects an `.env.development` file, which needs to be present in the batcher's root directory, rather than one directory above that. Once you have this set up, you can run the batcher using the following: 12 | 13 | ``` 14 | npm install 15 | npm run build 16 | npm run dev 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/batcher/address-validator/README.md: -------------------------------------------------------------------------------- 1 | # Paima Batcher Address Validator 2 | 3 | The address validator 4 | 5 | ## Usage 6 | 7 | Currently the library is in development, unpublished, and to be 8 | imported and used locally. 9 | 10 | ## Development 11 | 12 | Install dependencies: 13 | 14 | ``` 15 | npm i 16 | ``` 17 | 18 | To test: 19 | 20 | ``` 21 | npm run test 22 | ``` 23 | 24 | Lint: 25 | 26 | ``` 27 | npm run lint 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/batcher/address-validator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-address-validator", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc" 11 | }, 12 | "dependencies": { 13 | "pg": "^8.11.3", 14 | "web3": "1.10.0", 15 | "assert-never": "^1.2.1", 16 | "@dcspark/carp-client": "^3.1.0" 17 | }, 18 | "devDependencies": { 19 | "@types/pg": "^8.10.9" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/batcher/address-validator/src/date-utils.ts: -------------------------------------------------------------------------------- 1 | export function isSameDay(date1: Date, date2: Date): boolean { 2 | return ( 3 | date1.getUTCFullYear() === date2.getUTCFullYear() && 4 | date1.getUTCMonth() === date2.getUTCMonth() && 5 | date1.getUTCDate() === date2.getUTCDate() 6 | ); 7 | } 8 | 9 | export function isSameMinute(date1: Date, date2: Date): boolean { 10 | return ( 11 | isSameDay(date1, date2) && 12 | date1.getUTCHours() === date2.getUTCHours() && 13 | date1.getUTCMinutes() === date2.getUTCMinutes() 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/batcher/address-validator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../utils" }, 10 | { "path": "../db" }, 11 | { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, 12 | { "path": "../../paima-sdk/paima-crypto/tsconfig.build.json" }, 13 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/.dockerignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | .vscode 3 | node_modules 4 | **/node_modules 5 | **/build 6 | **/tsconfig.buildinfo 7 | 8 | # code formatter 9 | .eslintrc 10 | .eslintignore 11 | .editorconfig 12 | .huskyrc 13 | .lintstagedrc.json 14 | .prettierrc 15 | 16 | # docker 17 | Dockerfile 18 | docker-compose.yml 19 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/.gitignore: -------------------------------------------------------------------------------- 1 | # secret configs 2 | .env 3 | .env.development 4 | .env.production 5 | 6 | # DB 7 | snapshots 8 | 9 | # Generated, copied, compiled and fetched files that are included in the executable 10 | packaged 11 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/esbuildconfig.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const esbuild = require('esbuild'); 3 | const fs = require('fs'); 4 | 5 | void esbuild.build({ 6 | platform: 'node', 7 | entryPoints: ['../runtime/build/index.js'], 8 | bundle: true, 9 | format: 'cjs', 10 | outfile: 'packaged/batcherCorePacked.js', 11 | external: ['pg-native'], 12 | }); 13 | 14 | console.log('✅ Paima-batcher re-bundled successfully.'); 15 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/scripts/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # Common build stage 2 | FROM node:20.11.0 as common-build-stage 3 | 4 | COPY . ./app 5 | 6 | WORKDIR /app 7 | 8 | ARG BATCHER_PORT 9 | ENV EXPOSED_BATCHER_PORT=$BATCHER_PORT 10 | EXPOSE ${EXPOSED_BATCHER_PORT} 11 | 12 | # Production build stage 13 | FROM common-build-stage as production-build-stage 14 | 15 | ENV NODE_ENV production 16 | 17 | CMD ["./paima-batcher-linux"] 18 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/scripts/docker/shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | export ENV_FILE="../.env.${NETWORK:-localhost}"; 5 | docker compose --env-file $ENV_FILE down -v 6 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/scripts/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | executable="./paima-batcher-linux" 5 | 6 | # Check if the operating system is macOS using uname 7 | if [ "$(uname -s)" = "Darwin" ]; then 8 | executable="paima-batcher-macos" 9 | fi 10 | 11 | if [ ! -x $executable ]; then chmod +x $executable; fi 12 | 13 | export ENV_FILE="../.env.${NETWORK:-localhost}"; 14 | echo ENV FILE: $ENV_FILE; 15 | docker compose --env-file $ENV_FILE build 16 | 17 | # running a localhost node on your machine isn't exposed to docker which runs in a container 18 | # so when using a localhost network, we instead run the paima-batcher directly on the machine 19 | if [ -z "${NETWORK:-}" ] || [ "${NETWORK:-}" = "localhost" ]; then 20 | cp ../.env.${NETWORK:-localhost} . 21 | docker compose --env-file $ENV_FILE up paima-batcher-db & sleep 3 && BATCHER_DB_HOST=localhost $executable 22 | else 23 | if [[ ! -f "./paima-batcher-linux" ]]; then 24 | echo "Error: paima-batcher-linux binary not found. Docker requires the linux binary for the application." 25 | exit 1 26 | fi 27 | 28 | docker compose --env-file $ENV_FILE up 29 | fi 30 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/scripts/post_build.sh: -------------------------------------------------------------------------------- 1 | STANDALONE_DIR="./packaged/@standalone" 2 | SUBDIR="batcher" 3 | SUBDIR_BIN=$SUBDIR-bin 4 | 5 | echo "batcher post-build" 6 | 7 | # binaries 8 | mkdir -p "$STANDALONE_DIR/$SUBDIR_BIN/" 9 | mv "$STANDALONE_DIR/paima-batcher-linux" "$STANDALONE_DIR/$SUBDIR_BIN/" 2>/dev/null 10 | mv "$STANDALONE_DIR/paima-batcher-macos" "$STANDALONE_DIR/$SUBDIR_BIN/" 2>/dev/null 11 | mv "$STANDALONE_DIR/dev-paima-batcher-linux" "$STANDALONE_DIR/$SUBDIR_BIN/" 2>/dev/null 12 | mv "$STANDALONE_DIR/dev-paima-batcher-macos" "$STANDALONE_DIR/$SUBDIR_BIN/" 2>/dev/null 13 | 14 | # docker configs 15 | cp -r "./scripts/docker/." "$STANDALONE_DIR/$SUBDIR/" 16 | 17 | # default env vars 18 | ENV_TEMPLATE=.env.localhost 19 | cp "../$ENV_TEMPLATE" "$STANDALONE_DIR/$SUBDIR/$ENV_TEMPLATE" 20 | 21 | # SQL initialization 22 | mkdir -p "$STANDALONE_DIR/$SUBDIR/db" 23 | cp -r "../db/migrations" "$STANDALONE_DIR/$SUBDIR/db/" -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/src/index.ts: -------------------------------------------------------------------------------- 1 | // currently we package paima-batcher/runtime instead of this file 2 | // we may want to change this if we add more commands to the batcher standalone 3 | console.log('Run the batcher runtime instead'); 4 | -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "files": [], 4 | } -------------------------------------------------------------------------------- /packages/batcher/batcher-standalone/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": ["src/**/*", "src/**/*.json"], 9 | "references": [ 10 | { "path": "../runtime" }, 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/batcher/batcher-transaction-poster/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-transaction-poster", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc" 11 | }, 12 | "devDependencies": { 13 | "@types/pg": "^8.10.9" 14 | }, 15 | "dependencies": { 16 | "@polkadot/util-crypto": "^12.6.2", 17 | "mqtt": "^5.7.3", 18 | "pg": "^8.11.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/batcher/batcher-transaction-poster/src/gas-limit.ts: -------------------------------------------------------------------------------- 1 | import { ENV } from '@paima/batcher-utils'; 2 | 3 | const BASE_GAS_COST = ENV.MAX_BASE_GAS; 4 | const GAS_COST_PER_BYTE = ENV.MAX_GAS_PER_BYTE; 5 | 6 | export function estimateGasLimit(size: number): number { 7 | return GAS_COST_PER_BYTE * size + BASE_GAS_COST; 8 | } 9 | -------------------------------------------------------------------------------- /packages/batcher/batcher-transaction-poster/src/index.ts: -------------------------------------------------------------------------------- 1 | import AvailBatchedTransactionPoster from './avail.js'; 2 | import EvmBatchedTransactionPoster from './evm.js'; 3 | import BatchedTransactionPoster from './transactionPoster.js'; 4 | 5 | export { AvailBatchedTransactionPoster, EvmBatchedTransactionPoster, BatchedTransactionPoster }; 6 | -------------------------------------------------------------------------------- /packages/batcher/batcher-transaction-poster/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../utils" }, 10 | { "path": "../db" }, 11 | { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, 12 | { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, 13 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 14 | { "path": "../../paima-sdk/paima-events/tsconfig.build.json" }, 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/batcher/db/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | # deps 11 | /node_modules 12 | node_modules 13 | dist 14 | dist-ssr 15 | *.local 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | # build 29 | build/ -------------------------------------------------------------------------------- /packages/batcher/db/README.md: -------------------------------------------------------------------------------- 1 | # Paima Batcher Database Queries 2 | 3 | A module facilitating interaction with the Batcher database 4 | 5 | ## Usage 6 | 7 | After making any changes to the queries in `src/sql/*.sql`, to make them actually reflect in the typescript code, you need to run the following: 8 | 9 | ``` 10 | npm run generate 11 | ``` 12 | 13 | This will generate the `.ts` files using `pgtyped`. To successfully run this, you also need a postgres instance running with a properly initialized database (see [`./migrations/up.sql`](./migrations/up.sql) for the initialization script) with credentials specified in [`./pgtypedconfig.json`](./pgtypedconfig.json). 14 | 15 | ## Development 16 | 17 | Install dependencies: 18 | 19 | ``` 20 | npm i 21 | ``` 22 | 23 | To test: 24 | 25 | ``` 26 | npm run test 27 | ``` 28 | 29 | Lint: 30 | 31 | ``` 32 | npm run lint 33 | ``` 34 | -------------------------------------------------------------------------------- /packages/batcher/db/migrations/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE unvalidated_game_inputs; 2 | DROP TABLE validated_game_inputs; 3 | DROP TABLE input_states; 4 | DROP TABLE user_tracking; 5 | 6 | DROP TYPE input_state; -------------------------------------------------------------------------------- /packages/batcher/db/migrations/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE unvalidated_game_inputs ( 2 | id SERIAL PRIMARY KEY, 3 | address_type INTEGER NOT NULL, 4 | user_address TEXT NOT NULL, 5 | game_input TEXT NOT NULL, 6 | millisecond_timestamp TEXT NOT NULL, 7 | user_signature TEXT NOT NULL 8 | ); 9 | 10 | CREATE TABLE validated_game_inputs ( 11 | id SERIAL PRIMARY KEY, 12 | address_type INTEGER NOT NULL, 13 | user_address TEXT NOT NULL, 14 | game_input TEXT NOT NULL, 15 | millisecond_timestamp TEXT NOT NULL, 16 | user_signature TEXT NOT NULL 17 | ); 18 | 19 | CREATE TYPE input_state AS ENUM ('validating', 'rejected', 'accepted', 'posted'); 20 | 21 | CREATE TABLE input_states ( 22 | input_hash TEXT PRIMARY KEY, 23 | current_state input_state NOT NULL, 24 | block_height INTEGER, 25 | transaction_hash TEXT, 26 | rejection_code INTEGER 27 | ); 28 | 29 | CREATE TABLE user_tracking ( 30 | user_address TEXT PRIMARY KEY, 31 | latest_timestamp TIMESTAMP NOT NULL, 32 | inputs_minute INTEGER NOT NULL, 33 | inputs_day INTEGER NOT NULL, 34 | inputs_total INTEGER NOT NULL 35 | ); -------------------------------------------------------------------------------- /packages/batcher/db/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-db", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc", 11 | "generate": "npx pgtyped -w -c pgtypedconfig.json" 12 | }, 13 | "dependencies": { 14 | "@pgtyped/runtime": "2.3.0" 15 | }, 16 | "devDependencies": { 17 | "@pgtyped/cli": "^2.3.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/batcher/db/pgtypedconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "transforms": [ 3 | { 4 | "mode": "sql", 5 | "include": "**/*.sql", 6 | "emitTemplate": "{{dir}}/{{name}}.queries.ts" 7 | }, 8 | { 9 | "mode": "ts", 10 | "include": "**/*.ts", 11 | "emitTemplate": "{{dir}}/{{name}}.types.ts" 12 | } 13 | ], 14 | "srcDir": "./src/", 15 | "failOnError": false, 16 | "camelCaseColumnNames": false, 17 | "db": { 18 | "dbName": "postgres", 19 | "user": "postgres", 20 | "password": "postgres", 21 | "host": "localhost", 22 | "port": 5532, 23 | "ssl": false 24 | } 25 | } -------------------------------------------------------------------------------- /packages/batcher/db/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sql/queries.queries.js'; 2 | -------------------------------------------------------------------------------- /packages/batcher/db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/batcher/game-input-validator/README.md: -------------------------------------------------------------------------------- 1 | # Paima Batcher Game Input Validator 2 | 3 | The game input validator 4 | 5 | ## Usage 6 | 7 | Currently the library is in development, unpublished, and to be 8 | imported and used locally. 9 | 10 | ## Development 11 | 12 | Install dependencies: 13 | 14 | ``` 15 | npm i 16 | ``` 17 | 18 | To test: 19 | 20 | ``` 21 | npm run test 22 | ``` 23 | 24 | Lint: 25 | 26 | ``` 27 | npm run lint 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/batcher/game-input-validator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-game-input-validator", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc" 11 | }, 12 | "devDependencies": { 13 | "@types/pg": "^8.10.9" 14 | }, 15 | "dependencies": { 16 | "pg": "^8.11.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/batcher/game-input-validator/src/default-validator.ts: -------------------------------------------------------------------------------- 1 | import { ENV } from '@paima/batcher-utils'; 2 | import type { ErrorCode, GameInputValidatorCore } from '@paima/batcher-utils'; 3 | import axios from 'axios'; 4 | 5 | type DefaultInputValidatorCore = GameInputValidatorCore; 6 | 7 | export const DefaultInputValidatorCoreInitializator = { 8 | async initialize(): Promise { 9 | return { 10 | async validate(gameInput: string, userAddress: string): Promise { 11 | const url = `${ENV.GAME_NODE_URI}/dry_run`; 12 | const result = await axios.get<{ valid: boolean }>(url, { 13 | params: { gameInput, userAddress }, 14 | }); 15 | return result.data?.valid === true ? 0 : 1; 16 | }, 17 | }; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /packages/batcher/game-input-validator/src/empty-validator.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorCode, GameInputValidatorCore } from '@paima/batcher-utils'; 2 | 3 | type EmptyInputValidatorCore = GameInputValidatorCore; 4 | 5 | export const EmptyInputValidatorCoreInitializator = { 6 | async initialize(): Promise { 7 | return { 8 | async validate(_gameInput: string, _userAddress: string): Promise { 9 | return 0; 10 | }, 11 | }; 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /packages/batcher/game-input-validator/src/errors.ts: -------------------------------------------------------------------------------- 1 | import { GameInputValidatorCoreType, GENERIC_ERROR_MESSAGES } from '@paima/batcher-utils'; 2 | import type { ErrorCode } from '@paima/batcher-utils'; 3 | 4 | function getSpecificErrors(validatorType: GameInputValidatorCoreType): Record { 5 | switch (validatorType) { 6 | case GameInputValidatorCoreType.DEFAULT: 7 | return {}; 8 | case GameInputValidatorCoreType.NO_VALIDATION: 9 | return {}; 10 | default: 11 | return {}; 12 | } 13 | } 14 | 15 | export function getErrors(validatorType: GameInputValidatorCoreType): Record { 16 | return { 17 | ...GENERIC_ERROR_MESSAGES, 18 | ...getSpecificErrors(validatorType), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/batcher/game-input-validator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../utils" }, 10 | { "path": "../db" }, 11 | { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, 12 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/batcher/runtime/README.md: -------------------------------------------------------------------------------- 1 | # Paima Batcher Runtime 2 | 3 | The overarching runtime. 4 | 5 | Currently the library is in development, unpublished, and to be 6 | imported and used locally. 7 | 8 | ## (Outdated) Usage 9 | 10 | To run the batcher, it is recommended to use the instructions in [the root `README.md`](../README.md), but some of the details of what needs to happen under the hood relevant directly to this package are briefly described here. 11 | 12 | Before running, you need to have an instance of postgres running with a database initialized with [`db/migrations/up.sql`](db/migrations/up.sql) (running the docker setup will do this for you). 13 | 14 | The runtime also expects various environment variables to be set -- see e.g. [`.env.localhost`](./.env.localhost). 15 | 16 | Finally, to run the batcher, simply compile the code, then run `node build/index.js`. 17 | -------------------------------------------------------------------------------- /packages/batcher/runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-runtime", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc", 11 | "dev": "DOTENV_CONFIG_PATH=../.env.development node --require dotenv/config ./build/index.js", 12 | "prod": "node ./build/index.js" 13 | }, 14 | "devDependencies": { 15 | "@types/express": "^4.17.20", 16 | "@types/pg": "^8.10.9" 17 | }, 18 | "dependencies": { 19 | "ethers": "6.11.1", 20 | "express": "^4.18.1", 21 | "pg": "^8.11.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/batcher/runtime/src/pg/pgPool.ts: -------------------------------------------------------------------------------- 1 | import pg from 'pg'; 2 | import { ENV } from '@paima/batcher-utils'; 3 | /** 4 | * Pool of Postgres connections to avoid overhead of connecting on every request. 5 | */ 6 | 7 | export const creds = { 8 | host: ENV.BATCHER_DB_HOST, 9 | user: ENV.BATCHER_DB_USER, 10 | password: ENV.BATCHER_DB_PW, 11 | database: ENV.BATCHER_DB_NAME, 12 | port: ENV.BATCHER_DB_PORT, 13 | }; 14 | 15 | export function initializePool(): pg.Pool { 16 | const pool = new pg.Pool(creds); 17 | // Don't let a pg restart kill the app 18 | pool.on('error', err => console.log('Postgres pool error:', err)); 19 | 20 | pool.on('connect', (_client: pg.PoolClient) => { 21 | // On each new client initiated, need to register for error(this is a serious bug on pg, the client throw errors although it should not) 22 | _client.on('error', (err: Error) => { 23 | console.log('Postgres pool error:', err); 24 | }); 25 | }); 26 | 27 | return pool; 28 | } 29 | -------------------------------------------------------------------------------- /packages/batcher/runtime/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { RequestHandler } from 'express'; 2 | import type { BatchedTransactionPoster } from '@paima/batcher-transaction-poster'; 3 | import type GameInputValidator from '@paima/batcher-game-input-validator'; 4 | import type { Pool } from 'pg'; 5 | import type { AvailJsProvider, EthersEvmProvider } from '@paima/providers'; 6 | 7 | export interface BatcherRuntimeInitializer { 8 | initialize: (pool: Pool) => BatcherRuntime; 9 | } 10 | 11 | export interface BatcherRuntime { 12 | addGET: (route: string, callback: RequestHandler) => void; 13 | addPOST: (route: string, callback: RequestHandler) => void; 14 | run: ( 15 | gameInputValidator: GameInputValidator, 16 | BatchedTransactionPoster: BatchedTransactionPoster, 17 | provider: EthersEvmProvider | AvailJsProvider, 18 | getCurrentBlock: () => Promise 19 | ) => Promise; 20 | } 21 | -------------------------------------------------------------------------------- /packages/batcher/runtime/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../webserver/" }, 10 | { "path": "../game-input-validator/" }, 11 | { "path": "../utils" }, 12 | { "path": "../batcher-transaction-poster" }, 13 | { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, 14 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 15 | { "path": "../../node-sdk/paima-utils-backend" }, 16 | { "path": "../../paima-sdk/paima-mw-core/tsconfig.json" }, 17 | { "path": "../../node-sdk/paima-broker/tsconfig.build.json" }, 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/batcher/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | } 4 | -------------------------------------------------------------------------------- /packages/batcher/utils/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | # deps 11 | /node_modules 12 | node_modules 13 | dist 14 | dist-ssr 15 | *.local 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | # build 29 | build/ -------------------------------------------------------------------------------- /packages/batcher/utils/README.md: -------------------------------------------------------------------------------- 1 | # Paima Batcher Utils 2 | 3 | Various helper functions and definitions 4 | 5 | ## Usage 6 | 7 | Currently the library is in development, unpublished, and to be 8 | imported and used locally. 9 | 10 | ## Development 11 | 12 | Install dependencies: 13 | 14 | ``` 15 | npm i 16 | ``` 17 | 18 | To test: 19 | 20 | ``` 21 | npm run test 22 | ``` 23 | 24 | Lint: 25 | 26 | ``` 27 | npm run lint 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/batcher/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-utils", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc" 11 | }, 12 | "dependencies": { 13 | "assert-never": "^1.2.1", 14 | "avail-js-sdk": "^0.2.12" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/batcher/utils/src/types.ts: -------------------------------------------------------------------------------- 1 | export type ErrorCode = number; 2 | 3 | export type ErrorMessageFxn = (errorCode: ErrorCode) => string; 4 | 5 | export interface GameInputValidatorCore { 6 | validate: (gameInput: string, userAddress: string) => Promise; 7 | } 8 | 9 | export const enum GenericRejectionCode { 10 | OK = 0, 11 | UNSUPPORTED_ADDRESS_TYPE = 1, 12 | INVALID_ADDRESS = 2, 13 | INVALID_SIGNATURE = 3, 14 | ADDRESS_NOT_ALLOWED = 4, 15 | 16 | INVALID_GAME_INPUT = 100, 17 | } 18 | 19 | export const enum GameInputValidatorCoreType { 20 | NO_VALIDATION, 21 | DEFAULT, 22 | } 23 | -------------------------------------------------------------------------------- /packages/batcher/utils/src/version.ts: -------------------------------------------------------------------------------- 1 | type VersionString = `${number}.${number}.${number}`; 2 | 3 | const VERSION_MAJOR: number = 0; 4 | const VERSION_MINOR: number = 0; 5 | const VERSION_PATCH: number = 1; 6 | 7 | export const VERSION_STRING: VersionString = `${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}`; 8 | -------------------------------------------------------------------------------- /packages/batcher/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 10 | { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, 11 | { "path": "../../paima-sdk/paima-mw-core/tsconfig.json" }, 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/batcher/webserver/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/batcher-webserver", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc" 11 | }, 12 | "dependencies": { 13 | "axios": "^1.7.2", 14 | "cors": "^2.8.5", 15 | "express": "^4.18.1", 16 | "pg": "^8.11.3" 17 | }, 18 | "devDependencies": { 19 | "@types/cors": "^2.8.12", 20 | "@types/express": "^4.17.20", 21 | "@types/node": "^20.11.0", 22 | "@types/pg": "^8.10.9" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/batcher/webserver/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../address-validator/" }, 10 | { "path": "../db/" }, 11 | { "path": "../utils" }, 12 | { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, 13 | { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, 14 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/README.md: -------------------------------------------------------------------------------- 1 | # Paima Build Utils 2 | 3 | A common place to store utility scripts to for building core Paima components 4 | 5 | These are provided as part of Paima itself to avoid the need for projects depending on Paima to know how to update their build scripts for every internal change in Paima engine 6 | 7 | **Note**: This module comes with both ESM and CommonJS files, but only the ESM files are exposed through `paima-sdk`. Use this module directly if you need CommonJS. 8 | 9 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 10 | **Note**: This is not part of the [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) package as typically you will want this in your `devDependencies` unlike `@paima/sdk`, and unlike `@paima/sdk` this package is not purely ESM modules. 11 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/build-utils", 3 | "version": "4.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Util functions to build the core parts of Paima projects", 8 | "exports": { 9 | "./scripts/*": { 10 | "require": "./scripts/*" 11 | }, 12 | "./*": { 13 | "import": "./build/esm/*.mjs", 14 | "require": "./build/cjs/*.cjs" 15 | } 16 | }, 17 | "files": [ 18 | "/build", 19 | "/scripts" 20 | ], 21 | "author": "Paima Studios", 22 | "license": "See license file", 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 26 | }, 27 | "homepage": "https://docs.paimastudios.com", 28 | "scripts": { 29 | "lint:eslint": "eslint .", 30 | "build": "tsc --project tsconfig.cjs.json && tsc --project tsconfig.esm.json" 31 | }, 32 | "bin": { 33 | "paima-build-middleware": "./scripts/esbuild.sh", 34 | "paima-reset-db": "./scripts/change-db.js" 35 | }, 36 | "peerDependencies": { 37 | "esbuild": "^0.19.11", 38 | "esbuild-plugin-polyfill-node": "^0.3.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/scripts/copyAssets.cjs: -------------------------------------------------------------------------------- 1 | function copyAssetsForBundle(outDir) { 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | (() => { 5 | let asyncApiPath = path.dirname(require.resolve('@paima/runtime')); 6 | 7 | const from = path.join(asyncApiPath, 'public'); 8 | const to = path.join(outDir, 'public'); 9 | 10 | fs.cpSync(from, to, { recursive: true }); 11 | })(); 12 | 13 | (() => { 14 | let modulePath = path.dirname(require.resolve('@dcspark/cardano-multiplatform-lib-nodejs')); 15 | 16 | const wasm = 'cardano_multiplatform_lib_bg.wasm'; 17 | 18 | const from = path.join(modulePath, wasm); 19 | 20 | fs.cpSync(from, path.join(outDir, wasm)); 21 | })(); 22 | 23 | (() => { 24 | let modulePath = path.dirname(require.resolve('swagger-ui-dist')); 25 | 26 | const from = modulePath; 27 | 28 | fs.cpSync(from, path.join(outDir, 'swagger-ui'), { recursive: true }); 29 | })(); 30 | } 31 | 32 | module.exports = { copyAssetsForBundle }; 33 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/scripts/esbuild.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | echo "Packaging Middleware" 4 | 5 | node --require dotenv/config ./esbuildconfig.cjs 6 | echo "Finished Packaging" 7 | 8 | echo "Vanilla Middleware (With Exports) Prepared In: packaged/middleware.js" 9 | 10 | # note: this will not work if the esbuild format is "iife" (it will create a broken file instead) 11 | head -n $(( $(grep -n '^export {' packaged/middleware.js | head -1 | cut -d: -f1) - 1 )) packaged/middleware.js > packaged/paimaMiddleware.js 12 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/src/middleware-esbuildconfig.template.mts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line require-extensions/require-extensions -- https://github.com/solana-labs/eslint-plugin-require-extensions/issues/11 2 | import * as buildScript from './middleware-esbuildconfig.template.cjs'; 3 | export default buildScript; 4 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/src/standalone-esbuildconfig.template.cts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import type esbuild from 'esbuild'; 3 | 4 | export function generateConfig( 5 | apiFolder: string, 6 | stfFolder: string, 7 | precompilesFolder: string, 8 | eventsFolder: string 9 | ): { 10 | config: esbuild.BuildOptions; 11 | outFiles: Record; 12 | workspace: string; 13 | } { 14 | const workspace = process.env.BUNDLE_WORKSPACE; 15 | if (!workspace) throw new Error('BUNDLE_WORKSPACE variable not set.'); 16 | 17 | if (!fs.existsSync(workspace)) throw new Error(`Invalid workspace: ${workspace}.`); 18 | 19 | const outFiles = { 20 | [apiFolder]: 'endpoints.cjs', 21 | [stfFolder]: 'gameCode.cjs', 22 | [precompilesFolder]: 'precompiles.cjs', 23 | [eventsFolder]: 'events.cjs', 24 | }; 25 | 26 | const config: esbuild.BuildOptions = { 27 | platform: 'node', 28 | entryPoints: [`${workspace}/src/index.ts`], 29 | bundle: true, 30 | format: 'cjs', 31 | outfile: `packaged/${outFiles[workspace]}`, 32 | external: ['pg-native'], 33 | }; 34 | return { 35 | config, 36 | workspace, 37 | outFiles, 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/src/standalone-esbuildconfig.template.mts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line require-extensions/require-extensions -- https://github.com/solana-labs/eslint-plugin-require-extensions/issues/11 2 | import * as buildScript from './standalone-esbuildconfig.template.cjs'; 3 | export default buildScript; 4 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | }, 6 | "include": ["src/**/*"], 7 | "references": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "build/cjs", 5 | "module": "commonjs", 6 | }, 7 | "include": ["src/**/*.cts"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "build/esm" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/build-utils/paima-build-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // need this just because a lot of tools depend on the existence of a tsconfig.json 3 | "extends": "./tsconfig.base.json" 4 | } -------------------------------------------------------------------------------- /packages/build-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | } 4 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenBaseType.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { AnchorContext } from '../../context/AnchorProvider.js'; 3 | import { IsLocalContext } from '../../context/IsLocalProvider.js'; 4 | 5 | const AikenBaseType = (props: { value: string; children: React.ReactNode }): React.ReactNode => { 6 | const rootAnchor = useContext(AnchorContext); 7 | const isLocal = useContext(IsLocalContext); 8 | 9 | const isPrimitive = ((): boolean => { 10 | switch (props.value) { 11 | case 'Int': 12 | case 'ByteArray': 13 | return true; 14 | default: 15 | return false; 16 | } 17 | })(); 18 | if (isPrimitive) { 19 | return props.value; 20 | } 21 | if (!isLocal) { 22 | return
{props.value}
; 23 | } 24 | return ( 25 | 26 | {props.value} 27 | 28 | ); 29 | }; 30 | 31 | export default AikenBaseType; 32 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenConstructorMap.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CommentBlock from '../utils/CommentBlock.js'; 3 | 4 | const AikenConstructorMap = (props: { 5 | title: string; 6 | description: string; 7 | children: React.ReactNode; 8 | }): React.ReactNode => { 9 | const childrenArray = React.Children.toArray(props.children); 10 | const commaSeparatedItems = childrenArray.reduce((acc, curr, index) => { 11 | if (index === 0) { 12 | return [curr]; 13 | } 14 | return [...acc, ', ', curr]; 15 | }, []); 16 | return ( 17 |
18 | 19 | {props.title} { {commaSeparatedItems} } 20 |
21 | ); 22 | }; 23 | 24 | export default AikenConstructorMap; 25 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenConstructorMapField.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AikenConstructorMapField = (props: { 4 | mapKey: string; 5 | children: React.ReactNode; 6 | }): React.ReactNode => { 7 | return ( 8 | <> 9 | {props.mapKey}: {props.children} 10 | 11 | ); 12 | }; 13 | 14 | export default AikenConstructorMapField; 15 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenConstructorSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CommentBlock from '../utils/CommentBlock.js'; 3 | 4 | const AikenConstructorSimple = (props: { title: string; description: string }): React.ReactNode => { 5 | return ( 6 |
7 | 8 | {props.title} 9 |
10 | ); 11 | }; 12 | 13 | export default AikenConstructorSimple; 14 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenConstructorTuple.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CommentBlock from '../utils/CommentBlock.js'; 3 | 4 | const AikenConstructorTuple = (props: { 5 | title: string; 6 | description: string; 7 | children: React.ReactNode; 8 | }): React.ReactNode => { 9 | const childrenArray = React.Children.toArray(props.children); 10 | const commaSeparatedItems = childrenArray.reduce((acc, curr, index) => { 11 | if (index === 0) { 12 | return [curr]; 13 | } 14 | return [...acc, ', ', curr]; 15 | }, []); 16 | return ( 17 |
18 | 19 | {props.title}({commaSeparatedItems}) 20 |
21 | ); 22 | }; 23 | 24 | export default AikenConstructorTuple; 25 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenDatum.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AikenRedeemer from './AikenRedeemer.js'; 3 | 4 | const AikenDatum = (props: { 5 | title: string; 6 | description: string; 7 | children: React.ReactNode; 8 | }): React.ReactNode => { 9 | return ; 10 | }; 11 | 12 | export default AikenDatum; 13 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenDefinitionBlock.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { TypeContext } from '../../context/TypesProvider.js'; 3 | 4 | const AikenDefinitionBlock = (props: { 5 | scope: string; 6 | isLocal: boolean; 7 | children: React.ReactNode; 8 | }): React.ReactNode => { 9 | const { addType } = useContext(TypeContext); 10 | React.useEffect(() => { 11 | addType({ 12 | category: props.scope, 13 | isLocal: props.isLocal, 14 | lines: [props.children], 15 | }); 16 | }, []); 17 | return <>; 18 | }; 19 | 20 | export default AikenDefinitionBlock; 21 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenDefinitions.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { TypeContext, default as TypesProvider } from '../../context/TypesProvider.js'; 3 | import OutlineBlock from '../utils/OutlineBlock.js'; 4 | 5 | const AikenDefinitions = (props: { children: React.ReactNode }): React.ReactNode => { 6 | const { types } = useContext(TypeContext); 7 | return ( 8 | <> 9 | 10 | 11 | ); 12 | }; 13 | 14 | const AikenDefinitionsWrapper = (props: { children: React.ReactNode }): React.ReactNode => { 15 | return ( 16 | 17 | {props.children} 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default AikenDefinitionsWrapper; 24 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenEnum.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import CommentBlock from '../utils/CommentBlock.js'; 3 | import { AnchorContext } from '../../context/AnchorProvider.js'; 4 | 5 | const AikenEnum = (props: { 6 | title: string; 7 | description: string; 8 | children: React.ReactNode; 9 | }): React.ReactNode => { 10 | const rootAnchor = useContext(AnchorContext); 11 | return ( 12 |
13 | 14 | 15 | {props.title} 16 | {' '} 17 | =
{props.children}
18 |
19 |
20 | ); 21 | }; 22 | 23 | export default AikenEnum; 24 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenListType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AikenListType = (props: { children: React.ReactNode }): React.ReactNode => { 4 | return <>{props.children}[]; 5 | }; 6 | 7 | export default AikenListType; 8 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenMapType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AikenMapType = (props: { 4 | mapKey: React.ReactNode; 5 | children: React.ReactNode; 6 | }): React.ReactNode => { 7 | return ( 8 | <> 9 | Map<{props.mapKey}, {props.children}> 10 | 11 | ); 12 | }; 13 | 14 | export default AikenMapType; 15 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenParameter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AikenParameter = (props: { 4 | title: string; 5 | description: string; 6 | children: React.ReactNode; 7 | }): React.ReactNode => { 8 | return ( 9 | <> 10 | {props.title} = {props.children} 11 | 12 | ); 13 | }; 14 | 15 | export default AikenParameter; 16 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenRedeemer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CommentBlock from '../utils/CommentBlock.js'; 3 | 4 | const AikenRedeemer = (props: { 5 | title: string; 6 | description: string; 7 | children: React.ReactNode; 8 | }): React.ReactNode => { 9 | return ( 10 | <> 11 | 12 | {props.title} = {props.children} 13 | 14 | ); 15 | }; 16 | 17 | export default AikenRedeemer; 18 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenTupleType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AikenTupleType = (props: { children: React.ReactNode[] }): React.ReactNode => { 4 | const childrenArray = React.Children.toArray(props.children); 5 | const commaSeparatedItems = childrenArray.reduce((acc, curr, index) => { 6 | if (index === 0) { 7 | return [curr]; 8 | } 9 | return [...acc, ', ', curr]; 10 | }, []); 11 | return <>({commaSeparatedItems}); 12 | }; 13 | 14 | export default AikenTupleType; 15 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenValidator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import OutlineBlock from '../utils/OutlineBlock.js'; 3 | import type { LineList } from '../utils/OutlineBlock.js'; 4 | 5 | const AikenValidator = (props: { 6 | title: string; 7 | description: string; 8 | datum?: React.ReactNode; 9 | redeemer: React.ReactNode; 10 | parameters: React.ReactNode[]; 11 | }): React.ReactNode => { 12 | const lists: LineList[] = []; 13 | if (props.datum) { 14 | lists.push({ 15 | category: 'Datum', 16 | isLocal: true, 17 | lines: [props.datum], 18 | }); 19 | } 20 | lists.push({ 21 | category: 'Redeemer', 22 | isLocal: true, 23 | lines: [props.redeemer], 24 | }); 25 | lists.push({ 26 | category: 'Parameters', 27 | isLocal: true, 28 | lines: props.parameters, 29 | }); 30 | return ( 31 | <> 32 | {props.description} 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default AikenValidator; 39 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/aiken/AikenValidators.tsx: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | const AikenValidators = (props: { children: React.ReactNode }): React.ReactNode => { 4 | return props.children; 5 | }; 6 | 7 | export default AikenValidators; 8 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './aiken/index.js'; 2 | export * from './utils/index.js'; 3 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/utils/CommentBlock.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const CommentBlock = (props: { comment: string }): React.ReactNode => { 4 | if (props.comment.length === 0) return <>; 5 | if (props.comment.includes('\n')) { 6 | const lines = props.comment.split('\n'); 7 | return ( 8 | <> 9 | 10 | /** 11 |
12 | {lines.map((line, index) => ( 13 | <> 14 | {index !== 0 &&
} 15 |  * {line} 16 | 17 | ))} 18 |
19 |  */ 20 |
21 |
22 | 23 | ); 24 | } 25 | return ( 26 | <> 27 | // {props.comment} 28 |
29 | 30 | ); 31 | }; 32 | 33 | export default CommentBlock; 34 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/utils/HeaderWrapper.tsx: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | /** 4 | * For tools like Docusaurus, headers must be defined 5 | * - statically (ex: ## Foo) 6 | * - not dynamically (using tags like h1 in JSX) 7 | */ 8 | const HeaderWrapper = (props: { children: React.ReactNode }): React.ReactNode => { 9 | return props.children; 10 | }; 11 | 12 | export default HeaderWrapper; 13 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/components/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { default as CommentBlock } from './CommentBlock.js'; 2 | export { default as OutlineBlock } from './OutlineBlock.js'; 3 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/context/AnchorProvider.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext } from 'react'; 2 | 3 | export const AnchorContext = createContext(''); 4 | 5 | const AnchorProvider = (props: { children: React.ReactNode; anchor: string }): React.ReactNode => { 6 | return {props.children}; 7 | }; 8 | 9 | export default AnchorProvider; 10 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/context/IsLocalProvider.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext } from 'react'; 2 | 3 | export const IsLocalContext = createContext(false); 4 | 5 | const IsLocalProvider = (props: { 6 | children: React.ReactNode; 7 | isLocal: boolean; 8 | }): React.ReactNode => { 9 | return {props.children}; 10 | }; 11 | 12 | export default IsLocalProvider; 13 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/context/TypesProvider.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useState } from 'react'; 2 | import type { LineList } from '../components/utils/OutlineBlock.js'; 3 | 4 | // Create a context with an empty array as the default value 5 | export const TypeContext = createContext({ 6 | types: [] as LineList[], 7 | addType: (_type: LineList) => {}, 8 | }); 9 | 10 | const TypesProvider = (props: { children: React.ReactNode }): React.ReactNode => { 11 | const [types, setTypes] = useState([]); 12 | 13 | const addType = (type: LineList): void => { 14 | setTypes((prevTypes: LineList[]) => [...prevTypes, type]); 15 | }; 16 | 17 | return {props.children}; 18 | }; 19 | 20 | export default TypesProvider; 21 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/context/index.ts: -------------------------------------------------------------------------------- 1 | export { AnchorContext, default as AnchorProvider } from './AnchorProvider.js'; 2 | export { IsLocalContext, default as IsLocalProvider } from './IsLocalProvider.js'; 3 | export { TypeContext, default as TypesProvider } from './TypesProvider.js'; 4 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/index.js'; 2 | export * from './context/index.js'; 3 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/src/templates/prelude.hbs: -------------------------------------------------------------------------------- 1 | import { AikenBaseType } from '@paima/aiken-mdx'; 2 | import { AikenConstructorMap } from '@paima/aiken-mdx'; 3 | import { AikenConstructorMapField } from '@paima/aiken-mdx'; 4 | import { AikenConstructorSimple } from '@paima/aiken-mdx'; 5 | import { AikenConstructorTuple } from '@paima/aiken-mdx'; 6 | import { AikenDefinitionBlock } from '@paima/aiken-mdx'; 7 | import { AikenEnum } from '@paima/aiken-mdx'; 8 | import { AikenProject } from '@paima/aiken-mdx'; 9 | import { AikenListType } from '@paima/aiken-mdx'; 10 | import { AikenMapType } from '@paima/aiken-mdx'; 11 | import { AikenParameter } from '@paima/aiken-mdx'; 12 | import { AikenRedeemer } from '@paima/aiken-mdx'; 13 | import { AikenValidator } from '@paima/aiken-mdx'; 14 | import { AikenDatum } from '@paima/aiken-mdx'; 15 | import { AikenValidators } from '@paima/aiken-mdx'; 16 | import { AikenDefinitions } from '@paima/aiken-mdx'; 17 | import { AikenTupleType } from '@paima/aiken-mdx'; 18 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/.gitignore: -------------------------------------------------------------------------------- 1 | out/* 2 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/aiken-mdx-test/.gitignore: -------------------------------------------------------------------------------- 1 | # Aiken compilation artifacts 2 | artifacts/ 3 | # Aiken's project working directory 4 | build/ 5 | # Aiken's default documentation export 6 | docs/ 7 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/aiken-mdx-test/README.md: -------------------------------------------------------------------------------- 1 | # aiken-mdx-test 2 | 3 | A test contract for [aiken-mdx](https://www.npmjs.com/package/@paima/aiken-mdx) to test all the parsing rules 4 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/aiken-mdx-test/aiken.lock: -------------------------------------------------------------------------------- 1 | # This file was generated by Aiken 2 | # You typically do not need to edit this file 3 | 4 | [[requirements]] 5 | name = "aiken-lang/stdlib" 6 | version = "1.8.0" 7 | source = "github" 8 | 9 | [[requirements]] 10 | name = "aiken-lang/fuzz" 11 | version = "main" 12 | source = "github" 13 | 14 | [[requirements]] 15 | name = "aiken-lang/sparse-merkle-tree" 16 | version = "main" 17 | source = "github" 18 | 19 | [[packages]] 20 | name = "aiken-lang/stdlib" 21 | version = "1.8.0" 22 | requirements = [] 23 | source = "github" 24 | 25 | [[packages]] 26 | name = "aiken-lang/fuzz" 27 | version = "main" 28 | requirements = [] 29 | source = "github" 30 | 31 | [[packages]] 32 | name = "aiken-lang/sparse-merkle-tree" 33 | version = "main" 34 | requirements = [] 35 | source = "github" 36 | 37 | [etags] 38 | "aiken-lang/fuzz@main" = [{ secs_since_epoch = 1720147720, nanos_since_epoch = 291760159 }, "a8294651f1577c671d580c99c9bc5445ef1fd44e4aa3dde550434a4cbc8d50b6"] 39 | "aiken-lang/sparse-merkle-tree@main" = [{ secs_since_epoch = 1720147720, nanos_since_epoch = 891474127 }, "076db86c829f1bf2be5e996c9c1a714efcb761452d8abb8ae2b311e95c4aa6ed"] 40 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/aiken-mdx-test/aiken.toml: -------------------------------------------------------------------------------- 1 | name = "paima/aiken-mdx-test" 2 | version = "0.0.0" 3 | license = "Apache-2.0" 4 | description = "Aiken test contract for aiken-mdx" 5 | 6 | [repository] 7 | user = "PaimaStudios" 8 | project = "paima-engine" 9 | platform = "github" 10 | 11 | [[dependencies]] 12 | name = "aiken-lang/stdlib" 13 | version = "1.8.0" 14 | source = "github" 15 | 16 | [[dependencies]] 17 | name = "aiken-lang/fuzz" 18 | version = "main" 19 | source = "github" 20 | 21 | [[dependencies]] 22 | name = "aiken-lang/sparse-merkle-tree" 23 | version = "main" 24 | source = "github" 25 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/aiken-mdx-test/lib/aiken-mdx-test/utils.ak: -------------------------------------------------------------------------------- 1 | use aiken/builtin 2 | use aiken/transaction.{Datum, InlineDatum} 3 | 4 | pub fn get_inline_datum(datum: Datum) -> Data { 5 | expect InlineDatum(datum) = datum 6 | datum 7 | } 8 | 9 | pub fn skip_to(xs: List, index: Int) -> List { 10 | if index == 0 { 11 | xs 12 | } else { 13 | skip_to(builtin.tail_list(xs), index - 1) 14 | } 15 | } 16 | 17 | pub fn list_at(xs: List, index: Int) -> a { 18 | if index == 0 { 19 | builtin.head_list(xs) 20 | } else { 21 | list_at(builtin.tail_list(xs), index - 1) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/aiken-mdx-test/validators/whirl.ak: -------------------------------------------------------------------------------- 1 | use aiken/transaction.{OutputReference, ScriptContext} 2 | use aiken_mdx_test/validation.{MintActions, State, ValidateActions} 3 | 4 | // Foo comment 5 | validator(_init_ref: OutputReference) { 6 | fn minter(_rdmr: MintActions, _ctx: ScriptContext) -> Bool { 7 | fail 8 | } 9 | 10 | fn validate( 11 | _datum: State, 12 | _rdmr: ValidateActions, 13 | _ctx: ScriptContext, 14 | ) -> Bool { 15 | fail 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/test/multiple.hbs: -------------------------------------------------------------------------------- 1 | # Aiken Contracts 2 | 3 | Aiken contracts provided as part of Paima Engine. 4 | 5 | Core contracts 6 | 7 |
    8 |
  • [Inverse Whirlpool](#paima-inverse-whirlpool): Inverse whirlpool Aiken contract.
  • 9 |
10 | 11 | ## Core contracts 12 | 13 | {{{import "../inverse-whirlpool"}}} 14 | -------------------------------------------------------------------------------- /packages/cardano-contracts/aiken-mdx/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "build", 5 | "rootDir": "src", 6 | "noEmit": false, 7 | "jsx": "react", 8 | }, 9 | "include": ["./src/**/*"], 10 | } 11 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/.gitignore: -------------------------------------------------------------------------------- 1 | # Aiken compilation artifacts 2 | artifacts/ 3 | # Aiken's project working directory 4 | build/ 5 | # Aiken's default documentation export 6 | docs/ 7 | 8 | # JS deployment artifcats 9 | .env 10 | src/seed.txt 11 | src/package-lock.json 12 | src/node_modules 13 | 14 | # Additional files that the Aiken compiler produces or modifies 15 | /aiken.lock 16 | /plutus.json 17 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/aiken.toml: -------------------------------------------------------------------------------- 1 | name = "paima/inverse-whirlpool" 2 | version = "0.0.0" 3 | license = "Apache-2.0" 4 | description = "Aiken contracts for project Cardano inverse projection" 5 | 6 | [repository] 7 | user = "PaimaStudios" 8 | project = "paima-engine" 9 | platform = "github" 10 | 11 | [[dependencies]] 12 | name = "aiken-lang/stdlib" 13 | version = "1.9.0" 14 | source = "github" 15 | 16 | [[dependencies]] 17 | name = "aiken-lang/fuzz" 18 | version = "main" 19 | source = "github" 20 | 21 | [[dependencies]] 22 | name = "aiken-lang/sparse-merkle-tree" 23 | version = "main" 24 | source = "github" 25 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/lib/inverse_whirlpool/types/actions.ak: -------------------------------------------------------------------------------- 1 | use aiken/transaction.{OutputReference} 2 | 3 | pub type MintActionType { 4 | MintToken(OutputReference, TransactionBodyPieces, Metadata) 5 | BurnToken 6 | } 7 | 8 | pub type Metadata = 9 | ByteArray 10 | 11 | /// Ref: https://github.com/IntersectMBO/cardano-ledger/blob/master/eras/babbage/impl/cddl-files/babbage.cddl 12 | pub type TransactionBodyPieces { 13 | /// 7: auxiliary_data_hash 14 | metadata_hash: ByteArray, 15 | /// 13: set 16 | collateral_inputs: ByteArray, 17 | /// 16: transaction_output 18 | collateral_output: ByteArray, 19 | /// 17: coin 20 | collateral_fee: ByteArray, 21 | } 22 | 23 | // Spend validator to update the datum or retrieve ada or asset from address 24 | pub type SpendActions { 25 | Admin { action: AdminActionTypes } 26 | Minter { action: MintActionType } 27 | } 28 | 29 | pub type AdminActionTypes { 30 | UpdateDatum 31 | } 32 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/lib/inverse_whirlpool/types/data.ak: -------------------------------------------------------------------------------- 1 | use aiken/hash.{Blake2b_224, Hash} 2 | use aiken/transaction/credential.{VerificationKey} 3 | use aiken/transaction/value.{AssetName, PolicyId} 4 | 5 | /// Public key hash 6 | pub type VKeyHash = 7 | Hash 8 | 9 | /// Public key hash 10 | pub type State { 11 | mint: Int, 12 | } 13 | 14 | /// Number of tokens in circulation 15 | pub type ContractInfo { 16 | state: State, 17 | /// State (datum) on eUTXO 18 | lovelace: Int, 19 | } 20 | 21 | /// Lovelace on eUTXO 22 | pub type Asset { 23 | policy: PolicyId, 24 | /// Policy ID of the minting authority 25 | asset_name: AssetName, 26 | /// Name of asset in hexidecimal 27 | quantity: Int, 28 | } 29 | /// Number of token 30 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/lib/inverse_whirlpool/utils.ak: -------------------------------------------------------------------------------- 1 | use aiken/builtin 2 | use aiken/transaction.{Datum, InlineDatum} 3 | 4 | pub fn get_inline_datum(datum: Datum) -> Data { 5 | expect InlineDatum(datum) = datum 6 | datum 7 | } 8 | 9 | pub fn skip_to(xs: List
, index: Int) -> List { 10 | if index == 0 { 11 | xs 12 | } else { 13 | skip_to(builtin.tail_list(xs), index - 1) 14 | } 15 | } 16 | 17 | pub fn list_at(xs: List, index: Int) -> a { 18 | if index == 0 { 19 | builtin.head_list(xs) 20 | } else { 21 | list_at(builtin.tail_list(xs), index - 1) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/inverse-whirlpool", 3 | "version": "1.0.0", 4 | "description": "package.json wrapper for commands for this aiken project", 5 | "scripts": { 6 | "build": "aiken build && aiken check -D", 7 | "lint:eslint": "aiken fmt --check" 8 | }, 9 | "author": "Paima Studios", 10 | "license": "MIT", 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "@aiken-lang/aiken": "1.0.29-alpha" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/src/contract.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | export function getPlutusScript() { 4 | try { 5 | const data = JSON.parse(fs.readFileSync('../plutus.json', 'utf8')); 6 | return data; 7 | } catch (error) { 8 | console.error('Error reading plutus.json:', error); 9 | return null; // Or handle the error differently 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "src", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "execute": "node main.js", 8 | "dev": "vite", 9 | "build": "vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@commander-js/extra-typings": "^12.1.0", 14 | "dotenv": "^16.4.5", 15 | "lucid-cardano": "^0.10.7", 16 | "vue": "^3.4.21" 17 | }, 18 | "devDependencies": { 19 | "@vitejs/plugin-vue": "^5.0.4", 20 | "vite": "^5.2.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/cardano-contracts/inverse-whirlpool/validators/true.ak: -------------------------------------------------------------------------------- 1 | // This always-true validator allows us to mint tokens with arbitrary names 2 | // this allows using these token names as extra data input into the main whirlpool validator 3 | validator { 4 | fn mint(_action, _context) -> Bool { 5 | // Always true 6 | True 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | # Hardhat files 5 | /cache 6 | /artifacts 7 | 8 | # TypeChain files 9 | /typechain 10 | /typechain-types 11 | 12 | # solidity-coverage files 13 | /coverage 14 | /coverage.json 15 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/README.md: -------------------------------------------------------------------------------- 1 | # Paima EVM contracts 2 | 3 | NPM package for EVM contracts for Paima Engine and related utilities. 4 | 5 | See [the Paima documentation](https://docs.paimastudios.com/home/libraries/evm-contracts/introduction) for full documentation. 6 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/BaseState.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract BaseState { 8 | /// @dev Required payment for the NFT in sale. 9 | uint256 public nftPrice; 10 | 11 | /// @dev True if contract has been initialized via `initialize` function. 12 | bool public initialized; 13 | 14 | /// @dev Address of the NFT for sale. 15 | address public nftAddress; 16 | } 17 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/Proxy/OrderbookDexProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; 6 | 7 | /// @title Proxy contract for OrderbookDex 8 | contract OrderbookDexProxy is ERC1967Proxy { 9 | constructor( 10 | address _implementation, 11 | address _owner, 12 | uint256 _defaultMakerFee, 13 | uint256 _defaultTakerFee, 14 | uint256 _orderCreationFee 15 | ) 16 | ERC1967Proxy( 17 | _implementation, 18 | abi.encodeWithSignature( 19 | "initialize(address,uint256,uint256,uint256)", 20 | _owner, 21 | _defaultMakerFee, 22 | _defaultTakerFee, 23 | _orderCreationFee 24 | ) 25 | ) 26 | {} 27 | } 28 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/State.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract State { 8 | /// @dev Required payment for the NFT in sale. 9 | uint256 public nftPrice; 10 | 11 | /// @dev True if contract has been initialized via `initialize` function. 12 | bool public initialized; 13 | 14 | /// @dev Address of the NFT for sale. 15 | address public nftAddress; 16 | 17 | /// @dev Array of addresses of tokens that have been deposited to the contract via NFT sales. 18 | ERC20[] public depositedCurrencies; 19 | 20 | /// @dev Mapping that returns true for address of token that has been deposited to the contract via NFT sale. 21 | mapping(ERC20 => bool) public depositedCurrenciesMap; 22 | 23 | /// @dev Array of addresses of tokens that are accepted as payment for the NFT sale. 24 | ERC20[] public supportedCurrencies; 25 | } 26 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/dev/ERC721Dev.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 6 | 7 | contract Erc721Dev is ERC721 { 8 | constructor() ERC721("Mock ERC721", "MERC") {} 9 | 10 | function mint(address _to, uint256 _tokenId) external { 11 | _mint(_to, _tokenId); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/dev/Erc20Dev.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract Erc20Dev is ERC20 { 8 | constructor() ERC20("Mock ERC20", "MERC") {} 9 | 10 | function mint(address _to, uint256 _amount) external { 11 | _mint(_to, _amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/dev/NativeNftSaleUpgradeDev.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import "../NativeNftSale.sol"; 6 | import "./UpgradeDev.sol"; 7 | 8 | /// @dev For testing upgradeability. 9 | contract NativeNftSaleUpgradeDev is UpgradeDev, NativeNftSale {} 10 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/dev/NftSaleUpgradeDev.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import "../Erc20NftSale.sol"; 6 | 7 | /// @dev For testing upgradeability. 8 | contract NftSaleUpgradeDev is Erc20NftSale { 9 | function version() public pure returns (uint8) { 10 | return 2; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/dev/Token.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract Token is ERC20 { 8 | constructor(string memory name, string memory symbol) ERC20(name, symbol) { 9 | _mint(msg.sender, 10000000e18); 10 | } 11 | 12 | function mint(address _to, uint256 _amount) external { 13 | _mint(_to, _amount); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/dev/UpgradeDev.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | /// @dev For testing upgradeability. 6 | contract UpgradeDev { 7 | function version() public pure returns (uint8) { 8 | return 2; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/token/IERC4906Agnostic.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Forked from OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) 3 | 4 | pragma solidity ^0.8.13; 5 | 6 | /// @title Agnostic Metadata Update Extension 7 | interface IERC4906Agnostic { 8 | /// @dev This event emits when the metadata of a token is changed. 9 | /// So that the third-party platforms such as NFT market could 10 | /// timely update the images and related attributes of the token. 11 | event MetadataUpdate(uint256 _tokenId); 12 | 13 | /// @dev This event emits when the metadata of a range of tokens is changed. 14 | /// So that the third-party platforms such as NFT market could 15 | /// timely update the images and related attributes of the tokens. 16 | event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); 17 | } 18 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/token/ITokenUri.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.13; 3 | 4 | /// @dev An interface exposing the `tokenURI` function from IERC721Metadata. 5 | interface ITokenUri { 6 | /** 7 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 8 | */ 9 | function tokenURI(uint256 tokenId) external view returns (string memory); 10 | } 11 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/contracts/token/IUri.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.13; 3 | 4 | /// @dev An interface exposing the `uri` function from IERC1155MetadataURI. 5 | interface IUri { 6 | /** 7 | * @dev Returns the URI for token type `id`. 8 | * 9 | * If the `\{id\}` substring is present in the URI, it must be replaced by 10 | * clients with the actual token type ID. 11 | */ 12 | function uri(uint256 id) external view returns (string memory); 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/docs/templates/page.hbs: -------------------------------------------------------------------------------- 1 | import SolidityDetailBlock from '@site/src/components/SolidityDetailBlock'; 2 | import SolidityOutlineBlock from '@site/src/components/SolidityOutlineBlock'; 3 | import ContractHeader from '@site/src/components/ContractHeader'; 4 | 5 | {{#with-prelude}} 6 | {{readme (readme-path)}} 7 | {{/with-prelude}} -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/prepare.sh: -------------------------------------------------------------------------------- 1 | mkdir -p ./build 2 | 3 | # Include all our contracts in the build 4 | mkdir -p ./build/contracts 5 | cp -r ./contracts ./build 6 | rm -rf -r ./build/contracts/dev 7 | 8 | # ABI is generated during the build by hardhat-abi-exporter 9 | mkdir -p ./build/abi 10 | # remove dependencies and test contracts 11 | rm -rf -r ./build/abi/@openzeppelin 12 | rm -rf -r ./build/abi/contracts/dev 13 | # hoist content out of redundant "contracts" folder 14 | mv ./build/abi/contracts/* ./build/abi/ && rmdir ./build/abi/contracts 15 | 16 | # flatten ./MyContract.sol/MyContract.json to just ./MyContract.json 17 | find ./build/abi/ -type d -name '*.sol' -exec sh -c ' 18 | for dir; do 19 | mv "$dir"/* "$(dirname "$dir")/" 20 | rmdir "$dir" 21 | done 22 | ' sh {} + 23 | 24 | cp ./README.md ./build 25 | cp ./package.json ./build 26 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/src/index.ts: -------------------------------------------------------------------------------- 1 | import './paimaL2.js'; 2 | import './deployment.js'; 3 | export * from './recommendedHardhat.js'; 4 | export * from './deployment.js'; 5 | -------------------------------------------------------------------------------- /packages/contracts/evm-contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "build/plugin", 6 | "rootDir": "src", 7 | "noEmit": false, 8 | }, 9 | "include": ["./src/**/*"], 10 | } 11 | -------------------------------------------------------------------------------- /packages/engine/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | } 4 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-broker/README.md: -------------------------------------------------------------------------------- 1 | # Paima Broker 2 | 3 | ## Usage 4 | 5 | ### Start MQTT Server 6 | ```typescript 7 | new PaimaBroker().getServer('Paima-Engine'); 8 | ``` 9 | This creates a mqtt and websocket MQTT server 10 | 11 | ## Architecture 12 | 13 | ### Error handling 14 | 15 | ## Development 16 | 17 | Install dependencies: 18 | 19 | ``` 20 | npm i 21 | ``` 22 | 23 | To test: 24 | 25 | ``` 26 | npm run test 27 | ``` 28 | 29 | Lint: 30 | 31 | ``` 32 | npm run lint 33 | ``` 34 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-broker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/broker", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Paima Event System. Broker, Publisher and Listener", 8 | "type": "module", 9 | "main": "build/index.js", 10 | "types": "build/index.d.ts", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc --build tsconfig.build.json" 24 | }, 25 | "devDependencies": { 26 | "@types/ip": "^1.1.3", 27 | "typescript": "^5.5.3" 28 | }, 29 | "dependencies": { 30 | "ip": "^2.0.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-broker/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './event-broker.js'; 2 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-broker/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/node-sdk/paima-broker/tsconfig.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "rootDir": ".", 6 | "noEmit": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | ], 11 | "references": [ 12 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 13 | ] 14 | } -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # compose file for booting a temporary Postgres node for use with pgtyped 2 | services: 3 | database: 4 | image: postgres:16 5 | environment: 6 | PGUSER: postgres 7 | POSTGRES_PASSWORD: postgres 8 | volumes: 9 | - "./migrations/up.sql:/docker-entrypoint-initdb.d/up.sql" 10 | healthcheck: 11 | # Use pg_isready to check postgres is running. 12 | test: pg_isready -U postgres -p 5432 13 | interval: 20s 14 | timeout: 5s 15 | retries: 5 16 | start_period: 30s 17 | start_interval: 1s 18 | ports: 19 | - "54322:5432" 20 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/docker-postgres.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | trap "docker compose down" EXIT 5 | 6 | if ! docker compose up --wait; then 7 | docker compose logs --no-log-prefix 8 | exit 1 9 | fi 10 | "$@" 11 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/migrations/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE emulated_block_heights; 2 | DROP TABLE cde_erc20_data; 3 | DROP TABLE cde_erc721_data; 4 | DROP TABLE cde_erc20_deposit_data; 5 | DROP TABLE cde_generic_data; 6 | DROP TABLE cde_erc6551_registry_data; 7 | DROP TABLE chain_data_extensions; 8 | DROP TABLE cde_tracking; 9 | DROP TABLE rollup_inputs; 10 | DROP TABLE rollup_input_result; 11 | DROP TABLE rollup_input_origin; 12 | DROP TABLE nonces; 13 | DROP TABLE paima_blocks; 14 | DROP TABLE delegations; 15 | DROP TABLE addresses; 16 | DROP TABLE cde_cardano_pool_delegation; 17 | DROP TABLE cde_tracking_cardano; 18 | DROP TABLE cde_cardano_projected_nft; 19 | DROP TABLE cde_cardano_asset_utxos; 20 | DROP TABLE cde_tracking_cursor_pagination; 21 | DROP TABLE cde_cardano_transfer; 22 | DROP TABLE cde_cardano_mint_burn; 23 | DROP TABLE mina_checkpoint; 24 | DROP TABLE midnight_checkpoint; 25 | DROP TABLE achievement_progress; 26 | DROP TABLE cde_dynamic_primitive_config; 27 | DROP TABLE event; 28 | DROP TABLE registered_event; 29 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/db", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Library for Paima database interaction", 8 | "main": "build/index.js", 9 | "type": "module", 10 | "types": "build/index.d.ts", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "compile": "./docker-postgres.sh pgtyped -w -c pgtypedconfig.json", 24 | "build": "tsc" 25 | }, 26 | "devDependencies": { 27 | "@pgtyped/cli": "^2.3.0", 28 | "@types/node": "^20.11.0" 29 | }, 30 | "dependencies": { 31 | "pg": "^8.11.3", 32 | "pg-tx": "^1.0.1", 33 | "@pgtyped/runtime": "2.3.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/pgtypedconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "transforms": [ 3 | { 4 | "mode": "sql", 5 | "include": "**/*.sql", 6 | "emitTemplate": "{{dir}}/{{name}}.queries.ts" 7 | }, 8 | { 9 | "mode": "ts", 10 | "include": "**/*.ts", 11 | "emitTemplate": "{{dir}}/{{name}}.types.ts" 12 | } 13 | ], 14 | "srcDir": "./src/", 15 | "failOnError": false, 16 | "camelCaseColumnNames": false, 17 | "db": { 18 | "dbName": "postgres", 19 | "user": "postgres", 20 | "password": "postgres", 21 | "host": "localhost", 22 | "port": 54322, 23 | "ssl": false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/event-indexing.ts: -------------------------------------------------------------------------------- 1 | import type { PoolClient } from 'pg'; 2 | 3 | export async function createIndexesForEvents( 4 | pool: PoolClient, 5 | eventDescriptions: { topic: string; fieldName: string; indexed: boolean }[] 6 | ): Promise { 7 | for (const event of eventDescriptions) { 8 | const indexName = `index_${event.topic.slice(0, 20)}_${event.fieldName.toLowerCase()}`; 9 | 10 | const checkQuery = `SELECT * FROM pg_indexes WHERE indexname = '${indexName}';`; 11 | 12 | const result = await pool.query(checkQuery); 13 | 14 | const createQuery = `CREATE INDEX ${indexName} ON event(topic, (data->>'${event.fieldName}'));`; 15 | const deleteQuery = `DROP INDEX ${indexName};`; 16 | 17 | if (result.rowCount === 0 && event.indexed) { 18 | await pool.query(createQuery); 19 | } 20 | 21 | if (result.rowCount !== 0 && !event.indexed) { 22 | await pool.query(deleteQuery); 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/pg-tx.ts: -------------------------------------------------------------------------------- 1 | import txImport from 'pg-tx'; 2 | 3 | export let tx: typeof txImport; 4 | 5 | if (txImport.hasOwnProperty('default')) { 6 | tx = (txImport as unknown as { default: typeof txImport }).default; 7 | } else { 8 | tx = txImport; 9 | } 10 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/register-events.ts: -------------------------------------------------------------------------------- 1 | import type { PoolClient } from 'pg'; 2 | import { getEventByTopic, getTopics, registerEventType } from './sql/events.queries.js'; 3 | 4 | export async function registerEventTypes( 5 | pool: PoolClient, 6 | eventDescriptions: { topic: string; name: string }[] 7 | ): Promise { 8 | const allStoredTopics = await getTopics.run(undefined, pool); 9 | 10 | // check that no events were deleted. 11 | for (const storedTopic of allStoredTopics) { 12 | const found = eventDescriptions.find(ed => ed.topic === storedTopic.topic); 13 | 14 | if (found === undefined) { 15 | return false; 16 | } 17 | } 18 | 19 | for (const event of eventDescriptions) { 20 | const registeredTopic = await getEventByTopic.run({ topic: event.topic }, pool); 21 | 22 | if (registeredTopic.length === 0) { 23 | await registerEventType.run({ name: event.name, topic: event.topic }, pool); 24 | } 25 | } 26 | 27 | return true; 28 | } 29 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/achievements.sql: -------------------------------------------------------------------------------- 1 | /* 2 | @name getAchievementProgress 3 | @param names -> (...) 4 | */ 5 | SELECT * FROM achievement_progress 6 | WHERE wallet = :wallet! 7 | AND ('*' in :names OR name IN :names) 8 | ; 9 | 10 | /* @name setAchievementProgress */ 11 | INSERT INTO achievement_progress (wallet, name, completed_date, progress, total) 12 | VALUES (:wallet!, :name!, :completed_date, :progress, :total) 13 | ON CONFLICT (wallet, name) 14 | DO UPDATE SET 15 | completed_date = EXCLUDED.completed_date, 16 | progress = EXCLUDED.progress, 17 | total = EXCLUDED.total; 18 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cardano-last-epoch.sql: -------------------------------------------------------------------------------- 1 | /* @name updateCardanoEpoch */ 2 | INSERT INTO cardano_last_epoch( 3 | id, 4 | epoch 5 | ) VALUES ( 6 | 0, 7 | :epoch! 8 | ) 9 | ON CONFLICT (id) DO 10 | UPDATE SET epoch = :epoch!; 11 | 12 | /* @name getCardanoEpoch */ 13 | SELECT epoch from cardano_last_epoch LIMIT 1; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-cardano-asset-utxos.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeCardanoAssetUtxosByAddress */ 2 | SELECT * FROM cde_cardano_asset_utxos 3 | WHERE 4 | address = :address! AND 5 | COALESCE(cip14_fingerprint = :cip14_fingerprint, policy_id = :policy_id, false); 6 | 7 | /* @name cdeInsertCardanoAssetUtxo */ 8 | INSERT INTO cde_cardano_asset_utxos( 9 | cde_name, 10 | address, 11 | tx_id, 12 | output_index, 13 | amount, 14 | cip14_fingerprint, 15 | policy_id, 16 | asset_name 17 | ) VALUES ( 18 | :cde_name!, 19 | :address!, 20 | :tx_id!, 21 | :output_index!, 22 | :amount!, 23 | :cip14_fingerprint!, 24 | :policy_id!, 25 | :asset_name 26 | ); 27 | 28 | /* @name cdeSpendCardanoAssetUtxo */ 29 | DELETE FROM cde_cardano_asset_utxos 30 | WHERE tx_id = :tx_id! 31 | AND output_index = :output_index! 32 | AND cip14_fingerprint = :cip14_fingerprint!; 33 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-cardano-mint-burn.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeCardanoMintBurnInsert */ 2 | INSERT INTO cde_cardano_mint_burn ( 3 | cde_name, 4 | tx_id, 5 | metadata, 6 | assets, 7 | input_addresses, 8 | output_addresses 9 | ) VALUES ( 10 | :cde_name!, 11 | :tx_id!, 12 | :metadata!, 13 | :assets!, 14 | :input_addresses!, 15 | :output_addresses! 16 | ); -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-cardano-pool-delegation.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeCardanoPoolGetAddressDelegation */ 2 | SELECT * FROM cde_cardano_pool_delegation 3 | WHERE address = :address! 4 | ORDER BY epoch; 5 | 6 | /* @name cdeCardanoPoolInsertData */ 7 | INSERT INTO cde_cardano_pool_delegation( 8 | cde_name, 9 | address, 10 | pool, 11 | epoch 12 | ) VALUES ( 13 | :cde_name!, 14 | :address!, 15 | :pool!, 16 | :epoch! 17 | ) ON CONFLICT (cde_name, epoch, address) DO 18 | UPDATE SET pool = :pool!; 19 | 20 | 21 | /* @name removeOldEntries */ 22 | DELETE FROM cde_cardano_pool_delegation 23 | WHERE (cde_name, epoch, address) NOT IN ( 24 | SELECT 25 | cde_name, epoch, address 26 | FROM cde_cardano_pool_delegation 27 | WHERE address = :address! 28 | ORDER BY epoch DESC 29 | LIMIT 2 30 | ) 31 | AND address = :address!; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-cardano-transfer.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeCardanoTransferInsert */ 2 | INSERT INTO cde_cardano_transfer ( 3 | cde_name, 4 | tx_id, 5 | raw_tx, 6 | metadata 7 | ) VALUES ( 8 | :cde_name!, 9 | :tx_id!, 10 | :raw_tx!, 11 | :metadata 12 | ); 13 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-cursor-tracking-pagination.sql: -------------------------------------------------------------------------------- 1 | /* @name getPaginationCursors */ 2 | select * from cde_tracking_cursor_pagination; 3 | 4 | /* @name updatePaginationCursor */ 5 | INSERT INTO cde_tracking_cursor_pagination( 6 | cde_name, 7 | cursor, 8 | finished 9 | ) VALUES ( 10 | :cde_name!, 11 | :cursor!, 12 | :finished! 13 | ) 14 | ON CONFLICT (cde_name) 15 | DO UPDATE SET cursor = :cursor!, finished = :finished!; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-erc20-deposit.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeErc20DepositGetTotalDeposited */ 2 | SELECT * FROM cde_erc20_deposit_data 3 | WHERE cde_name = :cde_name! 4 | AND wallet_address = :wallet_address!; 5 | 6 | /* @name cdeErc20DepositInsertTotalDeposited */ 7 | INSERT INTO cde_erc20_deposit_data( 8 | cde_name, 9 | wallet_address, 10 | total_deposited 11 | ) VALUES ( 12 | :cde_name!, 13 | :wallet_address!, 14 | :total_deposited! 15 | ); 16 | 17 | /* @name cdeErc20DepositUpdateTotalDeposited */ 18 | UPDATE cde_erc20_deposit_data 19 | SET 20 | total_deposited = :total_deposited! 21 | WHERE cde_name = :cde_name! 22 | AND wallet_address = :wallet_address!; 23 | 24 | /* @name cdeErc20DepositSelectAll */ 25 | SELECT * FROM cde_erc20_deposit_data 26 | WHERE cde_name = :cde_name!; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-erc20.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeErc20GetBalance */ 2 | SELECT * FROM cde_erc20_data 3 | WHERE cde_name = :cde_name! 4 | AND wallet_address = :wallet_address!; 5 | 6 | /* @name cdeErc20InsertBalance */ 7 | INSERT INTO cde_erc20_data( 8 | cde_name, 9 | wallet_address, 10 | balance 11 | ) VALUES ( 12 | :cde_name!, 13 | :wallet_address!, 14 | :balance! 15 | ); 16 | 17 | /* @name cdeErc20UpdateBalance */ 18 | UPDATE cde_erc20_data 19 | SET 20 | balance = :balance! 21 | WHERE cde_name = :cde_name! 22 | AND wallet_address = :wallet_address!; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-erc6551-registry.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeErc6551GetOwner */ 2 | SELECT * FROM cde_erc6551_registry_data 3 | WHERE cde_name = :cde_name! 4 | AND account_created = :account_created!; 5 | 6 | /* @name cdeErc6551GetOwnedAccounts */ 7 | SELECT * FROM cde_erc6551_registry_data 8 | WHERE cde_name = :cde_name! 9 | AND token_contract = :token_contract! 10 | AND token_id = :token_id!; 11 | 12 | /* @name cdeErc6551InsertRegistry */ 13 | INSERT INTO cde_erc6551_registry_data( 14 | cde_name, 15 | block_height, 16 | account_created, 17 | implementation, 18 | token_contract, 19 | token_id, 20 | chain_id, 21 | salt 22 | ) VALUES ( 23 | :cde_name!, 24 | :block_height!, 25 | :account_created!, 26 | :implementation!, 27 | :token_contract!, 28 | :token_id!, 29 | :chain_id!, 30 | :salt! 31 | ); 32 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-generic.sql: -------------------------------------------------------------------------------- 1 | /* @name cdeGenericGetAllData */ 2 | SELECT * FROM cde_generic_data 3 | WHERE cde_name = :cde_name!; 4 | 5 | /* @name cdeGenericGetBlockheightData */ 6 | SELECT * FROM cde_generic_data 7 | WHERE cde_name = :cde_name! 8 | AND block_height = :block_height!; 9 | 10 | /* @name cdeGenericGetRangeData */ 11 | SELECT * FROM cde_generic_data 12 | WHERE cde_name = :cde_name! 13 | AND block_height >= :from_block! 14 | AND block_height <= :to_block!; 15 | 16 | /* @name cdeGenericInsertData */ 17 | INSERT INTO cde_generic_data( 18 | cde_name, 19 | block_height, 20 | event_data 21 | ) VALUES ( 22 | :cde_name!, 23 | :block_height!, 24 | :event_data! 25 | ); -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/cde-tracking.sql: -------------------------------------------------------------------------------- 1 | /* @name markCdeBlockheightProcessed */ 2 | INSERT INTO cde_tracking(block_height, caip2) 3 | VALUES (:block_height!, :caip2!); 4 | 5 | /* @name getLatestProcessedCdeBlockheight */ 6 | SELECT block_height FROM cde_tracking 7 | WHERE caip2 = :caip2! 8 | ORDER BY block_height DESC 9 | LIMIT 1; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/dynamic-primitives.sql: -------------------------------------------------------------------------------- 1 | /* @name getDynamicExtensions */ 2 | SELECT * FROM cde_dynamic_primitive_config; 3 | 4 | /* @name getDynamicExtensionsByParent */ 5 | SELECT * FROM cde_dynamic_primitive_config 6 | WHERE parent = :parent!; 7 | 8 | /* @name getDynamicExtensionByName */ 9 | SELECT * FROM cde_dynamic_primitive_config 10 | WHERE cde_name = :name!; 11 | 12 | /* @name insertDynamicExtension */ 13 | INSERT INTO cde_dynamic_primitive_config( 14 | cde_name, 15 | parent, 16 | config 17 | ) 18 | SELECT 19 | :base_name! || COUNT(*), 20 | :parent_name!, 21 | :config! 22 | FROM 23 | cde_dynamic_primitive_config 24 | WHERE starts_with(cde_name, :base_name!); 25 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/emulated.sql: -------------------------------------------------------------------------------- 1 | /* @name emulatedSelectLatestPrior */ 2 | SELECT * FROM emulated_block_heights 3 | WHERE emulated_block_height <= :emulated_block_height! 4 | ORDER BY deployment_chain_block_height DESC 5 | LIMIT 1; 6 | 7 | /* 8 | @name upsertEmulatedBlockheight 9 | @param items -> ((deployment_chain_block_height, second_timestamp, emulated_block_height)...) 10 | */ 11 | INSERT INTO emulated_block_heights( 12 | deployment_chain_block_height, 13 | second_timestamp, 14 | emulated_block_height 15 | ) VALUES :items! 16 | ON CONFLICT DO NOTHING; 17 | 18 | /* @name deploymentChainBlockheightToEmulated */ 19 | SELECT emulated_block_height FROM emulated_block_heights 20 | WHERE deployment_chain_block_height = :deployment_chain_block_height!; 21 | 22 | /* @name emulatedBlockheightToDeploymentChain */ 23 | SELECT deployment_chain_block_height FROM emulated_block_heights 24 | WHERE emulated_block_height = :emulated_block_height!; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/events.sql: -------------------------------------------------------------------------------- 1 | /* @name getEvents */ 2 | SELECT * FROM event WHERE 3 | COALESCE(block_height >= :from, 1=1) AND 4 | COALESCE(block_height <= :to, 1=1) AND 5 | COALESCE(address = :address, 1=1) AND 6 | topic = :topic!; 7 | 8 | /* @name insertEvent */ 9 | INSERT INTO event ( 10 | topic, 11 | address, 12 | data, 13 | block_height, 14 | tx_index, 15 | log_index 16 | ) VALUES ( 17 | :topic!, 18 | :address!, 19 | :data!, 20 | :block_height!, 21 | :tx_index!, 22 | :log_index! 23 | ); 24 | 25 | /* @name registerEventType */ 26 | INSERT INTO registered_event ( 27 | name, 28 | topic 29 | ) VALUES ( 30 | :name!, 31 | :topic! 32 | ); 33 | 34 | /* @name getTopicsForEvent */ 35 | SELECT topic FROM registered_event WHERE name = :name!; 36 | 37 | /* @name getTopics */ 38 | SELECT name, topic FROM registered_event; 39 | 40 | /* @name getEventByTopic */ 41 | SELECT name FROM registered_event WHERE topic = :topic!; -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/midnight-funnel.sql: -------------------------------------------------------------------------------- 1 | /* @name updateMidnightCheckpoint */ 2 | INSERT INTO midnight_checkpoint( 3 | caip2, 4 | block_height 5 | ) VALUES ( 6 | :caip2!, 7 | :block_height! 8 | ) 9 | ON CONFLICT (caip2) DO 10 | UPDATE SET block_height = :block_height!; 11 | 12 | /* @name getMidnightCheckpoint */ 13 | SELECT block_height FROM midnight_checkpoint WHERE caip2 = :caip2! LIMIT 1; 14 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/mina-checkpoints.sql: -------------------------------------------------------------------------------- 1 | /* @name updateMinaCheckpoint */ 2 | INSERT INTO mina_checkpoint( 3 | timestamp, 4 | caip2 5 | ) VALUES ( 6 | :timestamp!, 7 | :caip2! 8 | ) 9 | ON CONFLICT (caip2) DO 10 | UPDATE SET timestamp = :timestamp!; 11 | 12 | /* @name getMinaCheckpoint */ 13 | SELECT timestamp FROM mina_checkpoint WHERE caip2 = :caip2! LIMIT 1; 14 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/sql/nonces.sql: -------------------------------------------------------------------------------- 1 | /* @name findNonce */ 2 | SELECT * FROM nonces 3 | WHERE nonce = :nonce; 4 | 5 | /* @name deleteNonces */ 6 | DELETE FROM nonces 7 | WHERE block_height <= :limit_block_height!; 8 | 9 | /* @name insertNonce */ 10 | INSERT INTO nonces(nonce, block_height) 11 | VALUES (:nonce!, :block_height!); 12 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/table-types.ts: -------------------------------------------------------------------------------- 1 | type ColumnDataTuple = [ 2 | column_name: string, 3 | data_type: string, 4 | nullable: 'NO' | 'YES', 5 | default_value: string, 6 | ]; 7 | 8 | export interface ColumnData { 9 | columnName: string; 10 | columnType: string; 11 | columnNullable: string; 12 | defaultValue: string; 13 | } 14 | 15 | type TableIndex = { name: string; creationQuery: string }; 16 | export interface TableData { 17 | tableName: string; 18 | primaryKeyColumns: string[]; 19 | columnData: ColumnData[]; 20 | serialColumns: string[]; 21 | creationQuery: string; 22 | index?: TableIndex | TableIndex[]; 23 | } 24 | 25 | function packTuple(tuple: ColumnDataTuple): ColumnData { 26 | const [columnName, columnType, columnNullable, defaultValue] = tuple; 27 | return { 28 | columnName, 29 | columnType, 30 | columnNullable, 31 | defaultValue, 32 | }; 33 | } 34 | 35 | export function packTuples(tuples: ColumnDataTuple[]): ColumnData[] { 36 | return tuples.map(packTuple); 37 | } 38 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { PreparedQuery } from '@pgtyped/runtime'; 2 | 3 | export type SQLUpdate = [PreparedQuery, any]; 4 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ], 12 | "references": [ 13 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" } 14 | ] 15 | } -------------------------------------------------------------------------------- /packages/node-sdk/paima-engine/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/engine", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Paima Engine", 8 | "type": "module", 9 | "main": "build/index.js", 10 | "types": "build/index.d.ts", 11 | "files": [ 12 | "/build", 13 | "/scripts" 14 | ], 15 | "author": "Paima Studios", 16 | "license": "See license file", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 20 | }, 21 | "homepage": "https://docs.paimastudios.com", 22 | "scripts": { 23 | "lint:eslint": "eslint .", 24 | "build": "tsc" 25 | }, 26 | "dependencies": { 27 | "@paima/utils": "5.0.0", 28 | "@paima/funnel": "1.0.0", 29 | "@paima/runtime": "1.0.0", 30 | "@paima/rest": "1.0.0", 31 | "@paima/sm": "1.0.0" 32 | }, 33 | "devDependencies": { 34 | "typescript": "^5.5.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-engine/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": [ 8 | "src/**/*", 9 | ], 10 | "references": [ 11 | { "path": "../../paima-sdk/paima-events/tsconfig.build.json" }, 12 | { "path": "../paima-utils-backend" }, 13 | { "path": "../../paima-sdk/paima-chain-types/tsconfig.build.json" }, 14 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 15 | { "path": "../paima-funnel" }, 16 | { "path": "../paima-runtime/tsconfig.build.json" }, 17 | { "path": "../paima-sm" }, 18 | { "path": "../paima-rest/tsconfig.build.json" } 19 | ] 20 | } -------------------------------------------------------------------------------- /packages/node-sdk/paima-funnel/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | # deps 11 | /node_modules 12 | node_modules 13 | dist 14 | dist-ssr 15 | *.local 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | # build 29 | build/ 30 | node_modules 31 | *.tsbuildinfo 32 | cache/ -------------------------------------------------------------------------------- /packages/node-sdk/paima-funnel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/funnel", 3 | "version": "1.0.0", 4 | "description": "Blockchain Data fetching library for Paima Engine", 5 | "type": "module", 6 | "main": "build/index.js", 7 | "types": "build/index.d.ts", 8 | "files": [ 9 | "/build" 10 | ], 11 | "nx": { 12 | "implicitDependencies": [ 13 | "@paima/sm", 14 | "@paima/runtime" 15 | ] 16 | }, 17 | "scripts": { 18 | "lint:eslint": "eslint .", 19 | "build": "tsc" 20 | }, 21 | "author": "Paima Studios", 22 | "devDependencies": { 23 | "typescript": "^5.5.3" 24 | }, 25 | "dependencies": { 26 | "@dcspark/cardano-multiplatform-lib-nodejs": "5.2.0", 27 | "@dcspark/carp-client": "^3.1.0", 28 | "@midnight-ntwrk/compact-runtime": "^0.6.13", 29 | "@polkadot/util-crypto": "^12.6.2", 30 | "aedes": "^0.51.2", 31 | "aedes-server-factory": "^0.2.1", 32 | "assert-never": "^1.2.1", 33 | "avail-js-sdk": "^0.2.12", 34 | "graphql-ws": "^5.16.0", 35 | "mqtt": "^5.7.3", 36 | "pg": "^8.11.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-funnel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 10 | { "path": "../paima-runtime/tsconfig.build.json" }, 11 | { "path": "../../paima-sdk/paima-prando" }, 12 | { "path": "../../node-sdk/paima-db" }, 13 | { "path": "../../node-sdk/paima-utils-backend" }, 14 | { "path": "../../node-sdk/paima-sm" }, 15 | { "path": "../../paima-sdk/paima-crypto/tsconfig.build.json" }, 16 | { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, 17 | { "path": "../../paima-sdk/paima-chain-types/tsconfig.build.json" } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-rest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/rest", 3 | "version": "1.0.0", 4 | "description": "Paima Engine REST, defining the REST endpoints for the Paima node", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "npm run compile:api && tsc --build tsconfig.build.json", 11 | "prebuild": "", 12 | "compile:api": "tsoa spec-and-routes" 13 | }, 14 | "author": "Paima Studios", 15 | "dependencies": { 16 | "express": "^4.18.1", 17 | "http-status-codes": "^2.3.0", 18 | "tsoa": "^6.4.0", 19 | "yaml": "^2.3.1", 20 | "@paima/sm": "1.0.0" 21 | }, 22 | "devDependencies": { 23 | "@types/cors": "^2.8.12", 24 | "@types/express": "^4.17.20", 25 | "@types/node": "^20.11.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-rest/src/EngineService.ts: -------------------------------------------------------------------------------- 1 | import type { GameStateMachine } from '@paima/sm'; 2 | import type { AchievementMetadata } from '@paima/utils-backend'; 3 | 4 | export class EngineService { 5 | // Useful stuff 6 | readonly stateMachine: GameStateMachine; 7 | readonly achievements: Promise | null; 8 | 9 | constructor(alike: { 10 | readonly stateMachine: GameStateMachine; 11 | readonly achievements: Promise | null; 12 | }) { 13 | this.stateMachine = alike.stateMachine; 14 | this.achievements = alike.achievements; 15 | } 16 | 17 | getSM = (): GameStateMachine => this.stateMachine; 18 | 19 | // Singleton 20 | private static _instance?: EngineService; 21 | static get INSTANCE(): EngineService { 22 | if (!this._instance) { 23 | throw new Error('EngineService not initialized'); 24 | } 25 | return this._instance; 26 | } 27 | static set INSTANCE(value: EngineService) { 28 | this._instance = value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-rest/src/index.ts: -------------------------------------------------------------------------------- 1 | import { RegisterRoutes } from './tsoa/routes.js'; 2 | import { default as basicControllerJson } from './tsoa/swagger.json' with { type: 'json' }; 3 | export default RegisterRoutes; 4 | export { basicControllerJson }; 5 | export { EngineService } from './EngineService.js'; 6 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-rest/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "noEmit": false 7 | }, 8 | "include": ["src/**/*", "src/**/*.json"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-rest/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true 6 | }, 7 | "include": ["src/**/*", "test/**/*", "src/**/*.json"], 8 | "references": [ 9 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 10 | { "path": "../../node-sdk/paima-db" }, 11 | { "path": "../../node-sdk/paima-utils-backend" }, 12 | { "path": "../../node-sdk/paima-sm" } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-rest/tsoa.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryFile": "src/index.ts", 3 | "noImplicitAdditionalProperties": "throw-on-extras", 4 | "controllerPathGlobs": ["src/controllers/*.ts"], 5 | "spec": { 6 | "outputDirectory": "src/tsoa", 7 | "specVersion": 3, 8 | "operationIdTemplate": "{{replace controllerName 'Controller' ''}}{{titleCase method.name}}" 9 | }, 10 | "routes": { 11 | "routesDir": "src/tsoa", 12 | "esm": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/runtime", 3 | "version": "1.0.0", 4 | "description": "Paima Engine Runtime, Runtime which connects all the other portions of the Paima engine together", 5 | "main": "build/index.js", 6 | "type": "module", 7 | "types": "build/index.d.ts", 8 | "scripts": { 9 | "lint:eslint": "eslint .", 10 | "build": "tsc --build tsconfig.build.json && cp -r ./public ./build/public", 11 | "test": "vitest run" 12 | }, 13 | "author": "Paima Studios", 14 | "dependencies": { 15 | "@metamask/json-rpc-engine": "^9.0.2", 16 | "@sinclair/typebox": "^0.33.7", 17 | "@types/swagger-ui-express": "^4.1.6", 18 | "assert-never": "^1.2.1", 19 | "cors": "^2.8.5", 20 | "express": "^4.18.1", 21 | "fnv-plus": "^1.3.1", 22 | "json-stable-stringify": "^1.0.2", 23 | "openapi-merge": "^1.3.2", 24 | "swagger-ui-express": "^5.0.0", 25 | "viem": "^2.18.8", 26 | "yaml": "^2.3.1", 27 | "openapi-fetch": "^0.11.1" 28 | }, 29 | "devDependencies": { 30 | "@types/cors": "^2.8.12", 31 | "@types/express": "^4.17.20", 32 | "@types/fnv-plus": "^1.3.0", 33 | "@types/json-stable-stringify": "^1.0.34", 34 | "@types/node": "^20.11.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/public/asyncapi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/src/evm-rpc/types.ts: -------------------------------------------------------------------------------- 1 | import type { PublicRpcSchema } from 'viem'; 2 | 3 | export type PaimaEvmRpcSchema = [ 4 | ...PublicRpcSchema, 5 | { 6 | Method: 'eth_syncing'; 7 | Parameters?: undefined; 8 | /** 9 | * different EVM clients return different values for this 10 | * but the two seemingly common fields are 11 | * - startingBlock 12 | * - currentBlock 13 | */ 14 | ReturnType: boolean | { startingBlock: `0x${string}`; currentBlock: `0x${string}` }; 15 | }, 16 | ]; 17 | 18 | export type EvmRpcReturn = Extract< 19 | PaimaEvmRpcSchema[number], 20 | { Method: Method } 21 | >['ReturnType']; 22 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/src/nonce-gc.ts: -------------------------------------------------------------------------------- 1 | import type { Pool } from 'pg'; 2 | 3 | import { deleteNonces } from '@paima/db'; 4 | import { ENV, doLog } from '@paima/utils'; 5 | 6 | const BLOCKS_PER_MINUTE = Math.ceil(60 / ENV.BLOCK_TIME); 7 | const NONCE_GC_INTERVAL = 21600; // how often to do GC 8 | const NONCE_GC_LIFETIME = 7 * 24 * 60 * BLOCKS_PER_MINUTE; // minimum age of nonces to be deleted 9 | 10 | let nonceGcTrigger: number = ENV.SM_START_BLOCKHEIGHT; 11 | 12 | export async function cleanNoncesIfTime( 13 | DBPool: Pool, 14 | latestProcessedBlockHeight: number 15 | ): Promise { 16 | if (latestProcessedBlockHeight < nonceGcTrigger) { 17 | return; 18 | } 19 | nonceGcTrigger = Math.max(nonceGcTrigger, latestProcessedBlockHeight) + NONCE_GC_INTERVAL; 20 | const deletionLimit = latestProcessedBlockHeight - NONCE_GC_LIFETIME; 21 | const deleteUpTo = deletionLimit > 0 ? deletionLimit : 0; 22 | try { 23 | await deleteNonces.run({ limit_block_height: deleteUpTo }, DBPool); 24 | } catch (err) { 25 | doLog(`[paima-runtime::nonce-gc] Error while deleting nonces: ${err}`); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/src/run-flag.ts: -------------------------------------------------------------------------------- 1 | export let run = false; 2 | 3 | export const setRunFlag = (): void => { 4 | run = true; 5 | }; 6 | 7 | export const clearRunFlag = (): void => { 8 | run = false; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/test/config.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | import { parseCdeConfigFile } from '../src/cde-config/loading.js'; 3 | import * as fs from 'fs/promises'; 4 | 5 | // TODO: test if addresses get converted to lowercase properly 6 | 7 | describe('Test parsing CDE config files', () => { 8 | test(`parse CDE configs`, async () => { 9 | const configFileData = await fs.readFile('./test/example.yml', 'utf8'); 10 | expect(() => parseCdeConfigFile(configFileData, [])).not.toThrow(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/test/example.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | - name: 'ERC20 Deposit' 3 | type: 'erc20-deposit' 4 | contractAddress: '0xc7d688cb053c19ad5ee4f48c348958880537835f' 5 | startBlockHeight: 4567123 6 | scheduledPrefix: 'dp' 7 | depositAddress: '0xc7d688cb053c19ad5ee4f48c348958880537835f' 8 | 9 | - name: 'My ERC20 Contract' 10 | type: 'erc20' 11 | contractAddress: '0xc7d688cb053c19ad5ee4f48c348958880537835f' 12 | startBlockHeight: 4567123 13 | 14 | - name: 'My NFT Contract' 15 | type: 'erc721' 16 | contractAddress: '0xc7d688cb053c19ad5ee4f48c348958880537835f' 17 | startBlockHeight: 7654321 18 | scheduledPrefix: 'newnft' 19 | 20 | - name: 'My Custom Contract' 21 | type: 'generic' 22 | contractAddress: '0xc7d688cb053c19ad5ee4f48c348958880537835f' 23 | startBlockHeight: 11223344 24 | abiPath: './abis/MyCustomContract.json' 25 | eventSignature: 'MyEvent(address,uint256)' 26 | scheduledPrefix: 'cst' 27 | 28 | - name: 'ERC6551 Registration' 29 | type: 'erc6551-registry' 30 | startBlockHeight: 7654321 31 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "noEmit": false 7 | }, 8 | "include": ["src/**/*"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-runtime/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true 6 | }, 7 | "include": ["src/**/*", "test/**/*"], 8 | "references": [ 9 | { "path": "../../paima-sdk/paima-events/tsconfig.build.json" }, 10 | { "path": "../../paima-sdk/paima-chain-types/tsconfig.build.json" }, 11 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 12 | { "path": "../../node-sdk/paima-db" }, 13 | { "path": "../../paima-sdk/paima-mw-core" } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-sm/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ -------------------------------------------------------------------------------- /packages/node-sdk/paima-sm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/sm", 3 | "version": "1.0.0", 4 | "description": "Paima Studios Game Engine Library", 5 | "main": "build/index.js", 6 | "types": "build/index.d.ts", 7 | "type": "module", 8 | "files": [ 9 | "/build" 10 | ], 11 | "scripts": { 12 | "lint:eslint": "eslint .", 13 | "build": "tsc" 14 | }, 15 | "author": "Paima Studios", 16 | "dependencies": { 17 | "@sinclair/typebox": "^0.33.7", 18 | "assert-never": "^1.2.1", 19 | "@dcspark/carp-client": "^3.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-sm/src/cde-erc6551-registry.ts: -------------------------------------------------------------------------------- 1 | import type { CdeErc6551RegistryDatum } from './types.js'; 2 | import { cdeErc6551InsertRegistry } from '@paima/db'; 3 | import type { SQLUpdate } from '@paima/db'; 4 | 5 | export default async function processErc6551Datum( 6 | cdeDatum: CdeErc6551RegistryDatum 7 | ): Promise { 8 | const updateList: SQLUpdate[] = [ 9 | [ 10 | cdeErc6551InsertRegistry, 11 | { 12 | cde_name: cdeDatum.cdeName, 13 | block_height: cdeDatum.blockNumber, 14 | account_created: cdeDatum.payload.accountCreated, 15 | implementation: cdeDatum.payload.implementation, 16 | token_contract: cdeDatum.payload.tokenContract, 17 | token_id: cdeDatum.payload.tokenId, 18 | chain_id: cdeDatum.payload.chainId, 19 | salt: cdeDatum.payload.salt, 20 | }, 21 | ], 22 | ]; 23 | 24 | return updateList; 25 | } 26 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-sm/src/cde-erc721-mint.ts: -------------------------------------------------------------------------------- 1 | import { ENV } from '@paima/utils'; 2 | import type { CdeErc721MintDatum } from './types.js'; 3 | import { createScheduledData } from '@paima/db'; 4 | import type { SQLUpdate } from '@paima/db'; 5 | 6 | export default async function processErc721Datum( 7 | cdeDatum: CdeErc721MintDatum, 8 | inPresync: boolean 9 | ): Promise { 10 | const [address, prefix] = [cdeDatum.contractAddress, cdeDatum.scheduledPrefix]; 11 | if (!prefix) { 12 | return []; 13 | } 14 | const { tokenId, mintData } = cdeDatum.payload; 15 | const scheduledBlockHeight = inPresync ? ENV.SM_START_BLOCKHEIGHT + 1 : cdeDatum.blockNumber; 16 | const scheduledInputData = `${prefix}|${address}|${tokenId}|${mintData}`; 17 | return [ 18 | createScheduledData( 19 | scheduledInputData, 20 | { blockHeight: scheduledBlockHeight }, 21 | { 22 | cdeName: cdeDatum.cdeName, 23 | txHash: cdeDatum.transactionHash, 24 | caip2: cdeDatum.caip2, 25 | fromAddress: cdeDatum.payload.from, 26 | contractAddress: cdeDatum.contractAddress.toLowerCase(), 27 | } 28 | ), 29 | ]; 30 | } 31 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-sm/src/cde-midnight-contract-state.ts: -------------------------------------------------------------------------------- 1 | import { ENV } from '@paima/utils'; 2 | import type { CdeMidnightContractStateDatum } from './types.js'; 3 | import { createScheduledData } from '@paima/db'; 4 | import type { SQLUpdate } from '@paima/db'; 5 | 6 | export default async function processMidnightContractStateDatum( 7 | cdeDatum: CdeMidnightContractStateDatum, 8 | inPresync: boolean 9 | ): Promise { 10 | const { scheduledPrefix, payload, blockNumber } = cdeDatum; 11 | const updateList: SQLUpdate[] = []; 12 | 13 | const scheduledBlockHeight = inPresync ? ENV.SM_START_BLOCKHEIGHT + 1 : blockNumber; 14 | const scheduledInputData = [scheduledPrefix, payload].join('|'); 15 | updateList.push( 16 | createScheduledData( 17 | scheduledInputData, 18 | { blockHeight: scheduledBlockHeight }, 19 | { 20 | cdeName: cdeDatum.cdeName, 21 | txHash: cdeDatum.transactionHash, 22 | caip2: cdeDatum.caip2, 23 | fromAddress: '', // TODO: Midnight indexer doesn't serve this. 24 | contractAddress: cdeDatum.contractAddress, 25 | } 26 | ) 27 | ); 28 | 29 | return updateList; 30 | } 31 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-sm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, 10 | { "path": "../../node-sdk/paima-db" }, 11 | { "path": "../../paima-sdk/paima-prando" }, 12 | { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, 13 | { "path": "../../node-sdk/paima-utils-backend" }, 14 | { "path": "../../paima-sdk/paima-crypto/tsconfig.build.json" }, 15 | { "path": "../../paima-sdk/paima-events/tsconfig.build.json" }, 16 | { "path": "../../paima-sdk/paima-chain-types/tsconfig.build.json" }, 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ 5 | src/contract-types/ -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/README.md: -------------------------------------------------------------------------------- 1 | # Paima-utils-backend 2 | 3 | A simple library containing helper functions for other Paima backend libraries. This distinction is to support the separation of code targeting Node.js specifically from code targeting browsers specifically from code meant for use in both. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/utils-backend", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Library for Paima helper functions for use in backend", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^20.11.0" 27 | }, 28 | "dependencies": { 29 | "yaml": "^2.3.1", 30 | "@paima/db": "5.0.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/src/index.ts: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | export { parseSecurityYaml } from './security.js'; 4 | export * from './cde-access.js'; 5 | export type * from './types.js'; 6 | export * from './achievements.js'; 7 | 8 | export function hashTogether(data: string[]): string { 9 | return Crypto.createHash('sha256').update(data.join()).digest('base64'); 10 | } 11 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/src/security.ts: -------------------------------------------------------------------------------- 1 | import { ENV, parseAndValidateYAML } from '@paima/utils'; 2 | import * as fs from 'fs/promises'; 3 | 4 | export async function parseSecurityYaml(): Promise { 5 | const namespace = ENV.SECURITY_NAMESPACE; 6 | if (namespace.endsWith('.yml') || namespace.endsWith('.yaml')) { 7 | const content = await fs.readFile(ENV.SECURITY_NAMESPACE, 'utf-8'); 8 | parseAndValidateYAML(content); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/src/types.ts: -------------------------------------------------------------------------------- 1 | export type TokenIdPair = { tokenContract: string; tokenId: string }; 2 | 3 | export interface OwnedNftsResponse { 4 | cdeName: string; 5 | tokenId: bigint; 6 | } 7 | 8 | export interface GenericCdeDataUnit { 9 | blockHeight: number; 10 | payload: any; 11 | } 12 | 13 | export interface CardanoAssetUtxo { 14 | txId: string; 15 | outputIndex: number; 16 | amount: string; 17 | policyId: string; 18 | assetName: string; 19 | } 20 | -------------------------------------------------------------------------------- /packages/node-sdk/paima-utils-backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": ["src/**/*"], 9 | "references": [ 10 | { "path": "../paima-db" }, 11 | { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/README.md: -------------------------------------------------------------------------------- 1 | # Paima Node SDK 2 | 3 | Node-only portion of the SDK for Paima Engine. This package wraps all other core node-only packages of the Paima SDK, allowing to easily get access to all Paima features with a single dependency. This dependency can be excluded in frontends to compatibility with non-node based environments. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). 6 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/node-sdk", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Node SDK for Paima Engine", 8 | "type": "module", 9 | "author": "Paima Studios", 10 | "license": "See license file", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 14 | }, 15 | "homepage": "https://docs.paimastudios.com", 16 | "keywords": [ 17 | "autonomous worlds", 18 | "focg", 19 | "onchain game", 20 | "paima" 21 | ], 22 | "scripts": { 23 | "lint:eslint": "eslint .", 24 | "build:copy": "cp package.json ./build/ && cp README.md ./build/", 25 | "build": "npx tsc --build tsconfig.json && npm run build:copy" 26 | }, 27 | "devDependencies": {}, 28 | "dependencies": { 29 | "@paima/db": "5.0.0", 30 | "@paima/utils-backend": "5.0.0", 31 | "@paima/broker": "5.0.0", 32 | "@paima/engine": "5.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/node-sdk", 3 | "targets": { 4 | "nx-release-publish": { 5 | "dependsOn": ["^nx-release-publish"], 6 | "executor": "@nx/js:release-publish", 7 | "options": { 8 | "packageRoot": "{projectRoot}/build/" 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/src/broker.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/broker'; 2 | export type * from '@paima/broker'; 3 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/src/db.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/db'; 2 | export type * from '@paima/db'; 3 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/src/engine.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/engine'; 2 | export type * from '@paima/engine'; 3 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/src/utils-backend.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/utils-backend'; 2 | export type * from '@paima/utils-backend'; 3 | -------------------------------------------------------------------------------- /packages/node-sdk/publish-wrapper/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ], 12 | "files": [], 13 | "references": [ 14 | { "path": "../paima-db" }, 15 | { "path": "../paima-utils-backend" }, 16 | { "path": "../paima-broker/tsconfig.build.json" }, 17 | { "path": "../paima-engine" } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/node-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | } 4 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-chain-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/chain-types", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Core data types for Paima blocks", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc --build tsconfig.build.json" 24 | }, 25 | "devDependencies": { 26 | }, 27 | "dependencies": { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-chain-types/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hash.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-chain-types/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-chain-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["src/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ 5 | *.d.ts -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/README.md: -------------------------------------------------------------------------------- 1 | # Paima Concise Encoding Library library 2 | 3 | An encoding library that all games can use to build and consume concisely encoded game inputs. This library acts as one level of abstraction up from the game input strings, and supports abstractions such as the state identifier. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/concise", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Util library for concise encoding of game inputs", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "test": "vitest run", 24 | "build": "tsc --build tsconfig.build.json" 25 | }, 26 | "dependencies": { 27 | "ebnf": "^1.9.0", 28 | "web3-utils": "1.10.0" 29 | }, 30 | "devDependencies": { 31 | "@types/node": "^20.11.0", 32 | "@paima/utils": "5.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/src/index.ts: -------------------------------------------------------------------------------- 1 | export { builder } from './builder.js'; 2 | export { consumer } from './consumer.js'; 3 | export * from './PaimaParser.js'; 4 | export type * from './PaimaParser.js'; 5 | export * from './types.js'; 6 | export type * from './types.js'; 7 | export * from './batcher.js'; 8 | export type * from './batcher.js'; 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { HexString, InputString } from './types.js'; 2 | 3 | export const isHexString = (input: InputString): input is HexString => input.startsWith('0x'); 4 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/src/v1/builder.ts: -------------------------------------------------------------------------------- 1 | import type { ConciseValue, UTF8String } from '../types.js'; 2 | import { separator, stateIdentifier } from './consts.js'; 3 | 4 | const toString = (val: ConciseValue): string => { 5 | return val.isStateIdentifier ? `${stateIdentifier}${val.value}` : val.value; 6 | }; 7 | 8 | const build = (concisePrefix: string, conciseValues: ConciseValue[]): UTF8String => { 9 | if (!concisePrefix) { 10 | throw new Error(`Missing prefix value in concise builder for input: ${conciseValues}`); 11 | } 12 | const conciseValueInput = conciseValues.map(toString).join(separator); 13 | const conciseInput = `${concisePrefix}${separator}${conciseValueInput}`; 14 | 15 | return conciseInput; 16 | }; 17 | 18 | export default build; 19 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/src/v1/consts.ts: -------------------------------------------------------------------------------- 1 | import { INNER_BATCH_DIVIDER, OUTER_BATCH_DIVIDER } from '../batcher.js'; 2 | 3 | export const separator = '|'; 4 | export const stateIdentifier = '*'; 5 | 6 | export const FORBIDDEN_CHARACTERS = [separator, INNER_BATCH_DIVIDER, OUTER_BATCH_DIVIDER]; 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/src/v1/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ConciseValue } from '../types.js'; 2 | import { stateIdentifier } from './consts.js'; 3 | 4 | export const toConciseValue = (val: string): ConciseValue => { 5 | if (val.startsWith(stateIdentifier)) { 6 | return { value: val.replace(stateIdentifier, ''), isStateIdentifier: true }; 7 | } 8 | return { value: val, isStateIdentifier: false }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/test/paima-parser.at-user.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | import { PaimaParser, PaimaParserError } from '../src/PaimaParser.js'; 3 | 4 | const myGrammar = ` 5 | join = @j| 6 | `; 7 | 8 | const parserCommands = { 9 | join: {}, 10 | }; 11 | 12 | describe('Test single commands', () => { 13 | const startTest = (inputs: [string, boolean][]): void => { 14 | const parser = new PaimaParser(myGrammar, parserCommands); 15 | inputs.forEach((i: [string, boolean]) => { 16 | test(`${i[0]} to be ${i[1]}`, () => { 17 | try { 18 | const value = parser.start(i[0]); 19 | expect(!!value).toBe(i[1]); 20 | expect(value.command).toBe('join'); 21 | } catch (e) { 22 | if (e instanceof PaimaParserError) { 23 | expect(false).toBe(i[1]); 24 | } else { 25 | throw e; 26 | } 27 | } 28 | }); 29 | }); 30 | }; 31 | 32 | startTest([ 33 | ['j|T', false], 34 | ['j|', false], 35 | ['j', false], 36 | ['@j|T', true], 37 | ['@j|', true], 38 | ['@j', false], 39 | ]); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/test/paima-parser.single.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | import { PaimaParser, PaimaParserError } from '../src/PaimaParser.js'; 3 | 4 | const myGrammar = ` 5 | join = j| 6 | `; 7 | 8 | const parserCommands = { 9 | join: {}, 10 | }; 11 | 12 | describe('Test single commands', () => { 13 | const startTest = (inputs: [string, boolean][]): void => { 14 | const parser = new PaimaParser(myGrammar, parserCommands); 15 | inputs.forEach((i: [string, boolean]) => { 16 | test(`${i[0]} to be ${i[1]}`, () => { 17 | try { 18 | const value = !!parser.start(i[0]); 19 | expect(value).toBe(i[1]); 20 | } catch (e) { 21 | if (e instanceof PaimaParserError) { 22 | expect(false).toBe(i[1]); 23 | } else { 24 | throw e; 25 | } 26 | } 27 | }); 28 | }); 29 | }; 30 | 31 | startTest([ 32 | ['j|T', true], 33 | ['j|', true], 34 | ['j', false], 35 | ]); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-concise/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["test/**/*", "src/**/*"], 8 | "references": [ 9 | { "path": "../paima-utils/tsconfig.build.json" }, 10 | { "path": "../paima-chain-types/tsconfig.build.json" } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/config", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Configuration building for Paima", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "test": "vitest run", 24 | "build": "tsc --build tsconfig.build.json" 25 | }, 26 | "devDependencies": { 27 | }, 28 | "dependencies": { 29 | "@sinclair/typebox": "^0.33.7", 30 | "abitype": "1.0.6", 31 | "viem": "^2.21.3", 32 | "zod": "3.23.8" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/configCheck.ts: -------------------------------------------------------------------------------- 1 | import { toEventSignature } from 'viem'; 2 | import type { Abi } from 'abitype'; 3 | 4 | /** 5 | * TODO: delete this eventually 6 | * Unfortunately, there doesn't seem to be a static way to do this in viem 7 | * https://github.com/wevm/viem/discussions/2706 8 | */ 9 | export function checkEventExists( 10 | abi: ABI, 11 | signature: Signature 12 | ): Signature { 13 | const events = abi.filter(item => item.type === 'event'); 14 | for (const event of events) { 15 | // this is the part that returns `string` instead of a constant 16 | const eventSignature = toEventSignature(event); 17 | if (signature === eventSignature) { 18 | return signature; 19 | } 20 | } 21 | throw new Error(`Could not find event signature ${signature} in contract ABI`); 22 | } 23 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './configCheck.js'; 2 | export * from './ConfigBuilder.js'; 3 | export * from './schema/index.js'; 4 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/funnel/types.ts: -------------------------------------------------------------------------------- 1 | export enum ConfigFunnelType { 2 | EVM_MAIN = 'evm-main', 3 | EVM_PARALLEL = 'evm-parallel', 4 | CARDANO_PARALLEL = 'cardano-parallel', 5 | MINA_PARALLEL = 'mina-parallel', 6 | AVAIL_MAIN = 'avail-main', 7 | AVAIL_PARALLEL = 'avail-parallel', 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/index.ts: -------------------------------------------------------------------------------- 1 | export * from './funnel/index.js'; 2 | export * from './network/index.js'; 3 | export * from './primitive/index.js'; 4 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/network/evm.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@sinclair/typebox'; 2 | import type { Static } from '@sinclair/typebox'; 3 | import { ConfigSchema } from '../utils.js'; 4 | 5 | // =========== 6 | // Base schema 7 | // =========== 8 | 9 | export const ConfigNetworkSchemaEvm = new ConfigSchema({ 10 | required: Type.Object({ 11 | displayName: Type.String(), 12 | chainId: Type.Number(), 13 | chainUri: Type.String(), 14 | chainCurrencyName: Type.String(), 15 | chainCurrencySymbol: Type.String(), 16 | chainCurrencyDecimals: Type.Number(), 17 | }), 18 | optional: Type.Object({ 19 | chainExplorerUri: Type.String({ default: '' }), 20 | }), 21 | }); 22 | export type ConfigNetworkEvm = Static< 23 | ReturnType> 24 | >; 25 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/network/index.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@sinclair/typebox'; 2 | import type { ConfigNetworkType } from './types.js'; 3 | import { ConfigNetworkSchemaEvm } from './evm.js'; 4 | import type { ConfigNetworkEvm } from './evm.js'; 5 | export * from './evm.js'; 6 | export * from './types.js'; 7 | 8 | export type ConfigNetworkMapping = { 9 | [ConfigNetworkType.EVM]: ConfigNetworkEvm; 10 | // [ConfigNetworkType.CARDANO]: ConfigNetworkCardano; 11 | // [ConfigNetworkType.MINA]: ConfigNetworkMina; 12 | // [ConfigNetworkType.AVAIL]: ConfigNetworkAvail; 13 | }; 14 | 15 | // eslint-disable-next-line @typescript-eslint/explicit-function-return-type 16 | export const ConfigNetworkAll = (requireOptional: Bool) => 17 | Type.Union([ 18 | ConfigNetworkSchemaEvm.allProperties(requireOptional), 19 | // ConfigNetworkSchemaCardano.allProperties(requireOptional), 20 | // ConfigNetworkSchemaMina.allProperties(requireOptional), 21 | // ConfigNetworkSchemaAvail.allProperties(requireOptional), 22 | ]); 23 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/network/types.ts: -------------------------------------------------------------------------------- 1 | export enum ConfigNetworkType { 2 | EVM = 'evm', 3 | CARDANO = 'cardano', 4 | MINA = 'mina', 5 | AVAIL = 'avail', 6 | } 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/primitive/index.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@sinclair/typebox'; 2 | import { 3 | ChainDataExtensionDynamicEvmPrimitiveConfig, 4 | ChainDataExtensionErc1155Config, 5 | ChainDataExtensionErc20Config, 6 | ChainDataExtensionErc20DepositConfig, 7 | ChainDataExtensionErc6551RegistryConfig, 8 | ChainDataExtensionErc721Config, 9 | ChainDataExtensionGenericConfig, 10 | } from './evm.js'; 11 | export * from './evm.js'; 12 | export * from './types.js'; 13 | 14 | export const ConfigPrimitiveAll = Type.Union([ 15 | ChainDataExtensionErc20Config, 16 | ChainDataExtensionErc20DepositConfig, 17 | ChainDataExtensionErc721Config, 18 | ChainDataExtensionErc1155Config, 19 | ChainDataExtensionErc6551RegistryConfig, 20 | ChainDataExtensionGenericConfig, 21 | // ChainDataExtensionCardanoDelegationConfig, 22 | // ChainDataExtensionCardanoProjectedNFTConfig, 23 | // ChainDataExtensionCardanoDelayedAssetConfig, 24 | // ChainDataExtensionCardanoTransferConfig, 25 | // ChainDataExtensionCardanoMintBurnConfig, 26 | // ChainDataExtensionMinaEventGenericConfig, 27 | // ChainDataExtensionMinaActionGenericConfig, 28 | ChainDataExtensionDynamicEvmPrimitiveConfig, 29 | ]); 30 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/src/schema/primitive/types.ts: -------------------------------------------------------------------------------- 1 | export enum ConfigPrimitiveType { 2 | Generic = 'generic', 3 | ERC20 = 'erc20', 4 | ERC20Deposit = 'erc20-deposit', 5 | ERC721 = 'erc721', 6 | ERC6551Registry = 'erc6551-registry', 7 | ERC1155 = 'erc1155', 8 | CardanoDelegation = 'cardano-stake-delegation', 9 | CardanoProjectedNFT = 'cardano-projected-nft', 10 | CardanoDelayedAsset = 'cardano-delayed-asset', 11 | CardanoTransfer = 'cardano-transfer', 12 | CardanoMintBurn = 'cardano-mint-burn', 13 | MinaEventGeneric = 'mina-event-generic', 14 | MinaActionGeneric = 'mina-action-generic', 15 | DynamicEvmPrimitive = 'dynamic-evm-primitive', 16 | } 17 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["test/**/*", "src/**/*"], 8 | "references": [ 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ 5 | src/contract-types/ -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/README.md: -------------------------------------------------------------------------------- 1 | # Paima Crypto 2 | 3 | A library to handle the cryptography of all blockchains supported by Paima 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/crypto", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Library for cryptography of blockchains supported by Paima", 8 | "main": "build/index.js", 9 | "type": "module", 10 | "types": "build/index.d.ts", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc --build tsconfig.build.json", 24 | "test": "vitest run" 25 | }, 26 | "devDependencies": {}, 27 | "dependencies": { 28 | "web3": "1.10.0", 29 | "web3-utils": "1.10.0", 30 | "@cardano-foundation/cardano-verify-datasignature": "^1.0.11", 31 | "algosdk": "^2.3.0", 32 | "tweetnacl": "^1.0.3", 33 | "@polkadot/util": "^12.6.2", 34 | "@polkadot/util-crypto": "^12.6.2", 35 | "bech32": "^2.0.0", 36 | "@paima/utils": "5.0.0", 37 | "mina-signer": "^2.1.1", 38 | "bs58check": "^4.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/src/IVerify.ts: -------------------------------------------------------------------------------- 1 | export interface IVerify { 2 | verifyAddress(address: string): Promise; 3 | verifySignature(userAddress: string, message: string, signature: string): Promise; 4 | } 5 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/src/cardano.ts: -------------------------------------------------------------------------------- 1 | import { doLog } from '@paima/utils'; 2 | import type { IVerify } from './IVerify.js'; 3 | 4 | export class CardanoCrypto implements IVerify { 5 | verifyAddress = async (address: string): Promise => { 6 | // TODO: improve 7 | return await Promise.resolve(/^addr1[a-zA-Z0-9]+$/.test(address)); 8 | }; 9 | verifySignature = async ( 10 | userAddress: string, 11 | message: string, 12 | sigStruct: string 13 | ): Promise => { 14 | try { 15 | const [signature, key, ...remainder] = sigStruct.split('+'); 16 | if (!signature || !key || remainder.length > 0) { 17 | return false; 18 | } 19 | const { default: verifyCardanoDataSignature } = await import( 20 | '@cardano-foundation/cardano-verify-datasignature' 21 | ); 22 | return verifyCardanoDataSignature(signature, key, message, userAddress); 23 | } catch (err) { 24 | doLog('[address-validator] error verifying cardano signature:', err); 25 | return false; 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/src/evm.ts: -------------------------------------------------------------------------------- 1 | import { doLog } from '@paima/utils'; 2 | import type { IVerify } from './IVerify.js'; 3 | 4 | export class EvmCrypto implements IVerify { 5 | verifyAddress = async (address: string): Promise => { 6 | // TODO: improve 7 | return await Promise.resolve(/^0x[0-9A-Fa-f]+$/.test(address)); 8 | }; 9 | verifySignature = async ( 10 | userAddress: string, 11 | message: string, 12 | signature: string 13 | ): Promise => { 14 | try { 15 | const recoveredAddr = (await import('ethers')).verifyMessage(message, signature); 16 | return await Promise.resolve(recoveredAddr.toLowerCase() === userAddress.toLowerCase()); 17 | } catch (err) { 18 | doLog('[address-validator] error verifying evm signature:', err); 19 | return await Promise.resolve(false); 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/src/polkadot.ts: -------------------------------------------------------------------------------- 1 | import { doLog } from '@paima/utils'; 2 | import type { IVerify } from './IVerify.js'; 3 | 4 | export class PolkadotCrypto implements IVerify { 5 | verifyAddress = async (address: string): Promise => { 6 | // TODO: improve 7 | return await Promise.resolve(/^[1-9A-HJ-NP-Za-km-z]{47,48}$/.test(address)); 8 | }; 9 | verifySignature = async ( 10 | userAddress: string, 11 | message: string, 12 | signature: string 13 | ): Promise => { 14 | try { 15 | const { cryptoWaitReady, decodeAddress, signatureVerify } = await import( 16 | '@polkadot/util-crypto' 17 | ); 18 | const { u8aToHex } = await import('@polkadot/util'); 19 | await cryptoWaitReady(); 20 | const publicKey = decodeAddress(userAddress); 21 | const hexPublicKey = u8aToHex(publicKey); 22 | return signatureVerify(message, signature, hexPublicKey).isValid; 23 | } catch (err) { 24 | doLog('[address-validator] error verifying polkadot signature:', err); 25 | return false; 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | 3 | describe('Test if parsed', () => { 4 | test(`placeholder`, async () => { 5 | expect(false).toEqual(false); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-crypto/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["test/**/*", "src/**/*"], 8 | "references": [ 9 | { "path": "../paima-utils/tsconfig.build.json" } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-events/README.md: -------------------------------------------------------------------------------- 1 | # Paima Events: Publisher & Client 2 | 3 | ## Development 4 | 5 | Install dependencies: 6 | 7 | ``` 8 | npm i 9 | ``` 10 | 11 | To test: 12 | 13 | ``` 14 | npm run test 15 | ``` 16 | 17 | Lint: 18 | 19 | ``` 20 | npm run lint 21 | ``` 22 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-events/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/events", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Paima Event System. Broker, Publisher and Listener", 8 | "type": "module", 9 | "main": "build/index.js", 10 | "types": "build/index.d.ts", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc --build tsconfig.build.json", 24 | "test": "vitest run" 25 | }, 26 | "devDependencies": { 27 | "typescript": "^5.5.3" 28 | }, 29 | "dependencies": { 30 | "@sinclair/typebox": "^0.33.7", 31 | "abitype": "^1.0.6", 32 | "js-sha3": "^0.9.3", 33 | "mqtt": "^5.7.3", 34 | "mqtt-pattern": "^2.1.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-events/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app-events.js'; 2 | export * from './event-manager.js'; 3 | export * from './builtin-events.js'; 4 | export * from './builtin-event-utils.js'; 5 | export * from './utils.js'; 6 | export * from './event-connect.js'; 7 | export * from './builtin-event-utils.js'; 8 | export * from './types.js'; 9 | export * from './evm.js'; 10 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-events/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-events/tsconfig.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "rootDir": ".", 6 | "noEmit": true 7 | }, 8 | "include": ["test/**/*", "src/**/*"], 9 | "references": [ 10 | { "path": "../paima-utils/tsconfig.build.json" }, 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-executors/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | lib 10 | node_modules 11 | dist 12 | dist-ssr 13 | build 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | build/ 27 | node_modules 28 | *.tsbuildinfo 29 | cache/ -------------------------------------------------------------------------------- /packages/paima-sdk/paima-executors/README.md: -------------------------------------------------------------------------------- 1 | # Paima Executors 2 | 3 | Utility functions for different kinds of executors in Paima to build different abstraction layers over the base ticks such as matches and rounds. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-executors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/executors", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Utility functions for different kinds of executors in Paima", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc" 24 | }, 25 | "devDependencies": { 26 | "typescript": "^5.5.3" 27 | }, 28 | "dependencies": { 29 | "@paima/prando": "5.0.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-executors/src/index.ts: -------------------------------------------------------------------------------- 1 | import matchExecutor from './match_executor.js'; 2 | import roundExecutor from './round_executor.js'; 3 | export type * from './types.js'; 4 | 5 | export { matchExecutor, roundExecutor }; 6 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-executors/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [{ "path": "../paima-prando" }] 9 | } 10 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/README.md: -------------------------------------------------------------------------------- 1 | # Paima Middleware Core 2 | 3 | Middleware to facilitate connection of frontends written for games using Paima with a game node. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/endpoints/internal.ts: -------------------------------------------------------------------------------- 1 | import type { URI } from '@paima/utils'; 2 | import { setBackendUri } from '../state.js'; 3 | import type { Wallet } from '../types.js'; 4 | import { specificWalletLogin } from '../wallets/wallets.js'; 5 | import type { LoginInfo } from '../wallets/wallet-modes.js'; 6 | import type { Result } from '@paima/utils'; 7 | 8 | /** 9 | * @deprecated do not use this unless you are really sure. Instead, prefer `userWalletLogin` 10 | */ 11 | export async function userWalletLoginWithoutChecks( 12 | loginInfo: LoginInfo, 13 | setDefault: boolean = true 14 | ): Promise> { 15 | return await specificWalletLogin(loginInfo, setDefault); 16 | } 17 | 18 | export async function updateBackendUri(newUri: URI): Promise { 19 | setBackendUri(newUri); 20 | } 21 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/endpoints/queries.ts: -------------------------------------------------------------------------------- 1 | import { buildEndpointErrorFxn, PaimaMiddlewareErrorCode } from '../errors.js'; 2 | import { getRawLatestProcessedBlockHeight } from '../helpers/auxiliary-queries.js'; 3 | import type { Result } from '@paima/utils'; 4 | 5 | async function getLatestProcessedBlockHeight(): Promise> { 6 | const errorFxn = buildEndpointErrorFxn('getLatestProcessedBlockHeight'); 7 | try { 8 | return await getRawLatestProcessedBlockHeight(); 9 | } catch (err) { 10 | return errorFxn(PaimaMiddlewareErrorCode.UNKNOWN, err); 11 | } 12 | } 13 | 14 | export const queryEndpoints = { 15 | getLatestProcessedBlockHeight, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/endpoints/utility.ts: -------------------------------------------------------------------------------- 1 | import { joinLogs, pushLog as log } from '../helpers/logging.js'; 2 | 3 | const exportLogs = (): string => { 4 | return joinLogs(); 5 | }; 6 | 7 | /** 8 | * Re-exported simply to follow the structure of functions utilized from Unity 9 | */ 10 | export const utilityEndpoints = { 11 | exportLogs, 12 | pushLog: log, 13 | }; 14 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/global.d.ts: -------------------------------------------------------------------------------- 1 | import { MetaMaskInpageProvider } from '@metamask/providers'; 2 | 3 | declare global { 4 | interface Window { 5 | ethereum: MetaMaskInpageProvider; 6 | evmproviders?: { 7 | // API should be the same as MetaMask 8 | flint: MetaMaskInpageProvider; 9 | }; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/helpers/clients.ts: -------------------------------------------------------------------------------- 1 | import { getBackendUri, getBatcherUri } from '../state.js'; 2 | import createClient from 'openapi-fetch'; 3 | import type { Client } from 'openapi-fetch'; 4 | 5 | // generated by openapi-typescript 6 | import type { paths as PaimaNodePaths } from './paima-node-rest-schema.d.js'; 7 | export type { components as PaimaNodeRestComponents } from './paima-node-rest-schema.d.js'; 8 | // import type { paths as PaimaNodePaths } from './paima-batcher-rest-schema'; 9 | // export type { paths as PaimaNodePaths } from './paima-batcher-rest-schema'; 10 | 11 | let client: null | Client; 12 | 13 | export function getPaimaNodeRestClient(): Client { 14 | if (client == null) { 15 | client = createClient({ baseUrl: getBackendUri() }); 16 | } 17 | return client; 18 | } 19 | 20 | // export function getPaimaBatcherRestClient(): Client { 21 | // return createClient({ baseUrl: getBatcherUri() }); 22 | // } 23 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/helpers/logging.ts: -------------------------------------------------------------------------------- 1 | const LOG_LIMIT = 1000; 2 | let logBuffer: string[] = []; 3 | 4 | function stringify(blob: any): string { 5 | switch (typeof blob) { 6 | case 'object': 7 | if (Array.isArray(blob)) { 8 | return `${blob.map(stringify)}`; 9 | } else if (blob instanceof Error) { 10 | return `${blob.toString()}\n${blob.stack}`; 11 | } 12 | return JSON.stringify(blob); 13 | case 'function': 14 | return 'function'; 15 | default: 16 | return `${blob}`; 17 | } 18 | } 19 | 20 | export const pushLog = (message: any, ...optionalParams: any[]): void => { 21 | if (logBuffer.length >= LOG_LIMIT) { 22 | logBuffer.shift(); 23 | } 24 | 25 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 26 | console.log(message, ...optionalParams); 27 | const timestamp = new Date().toISOString(); 28 | const fileMessage = `[${timestamp}] ${stringify(message)} ${stringify(optionalParams)}`; 29 | logBuffer.push(fileMessage); 30 | }; 31 | 32 | export const joinLogs = (): string => { 33 | return logBuffer.join('\n'); 34 | }; 35 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/name-generation/index.ts: -------------------------------------------------------------------------------- 1 | import Prando from '@paima/prando'; 2 | import type { WalletAddress } from '@paima/chain-types'; 3 | import { adjectives } from './adjectives.js'; 4 | import { nouns } from './nouns.js'; 5 | 6 | // around 0.2% repetition with 10k users 7 | // around 1.5% repetition with 100k users 8 | // around 14.45% repetition with 1M users 9 | /** 10 | * @returns wallet address transformed into a pseudorandom name `Adjective Noun`. Longest possible name is 20 characters. 11 | */ 12 | export const walletToName = (wallet: WalletAddress): string => { 13 | const maxCharacters = 20; 14 | const prando = new Prando(wallet); 15 | const adjectiveLength = adjectives.length; 16 | const nounLength = nouns.length; 17 | while (true) { 18 | const adjective = adjectives[Math.floor(prando.next() * adjectiveLength)]; 19 | const noun = nouns[Math.floor(prando.next() * nounLength)]; 20 | const result = `${adjective} ${noun}`; 21 | if (result.length <= maxCharacters) return result; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/wallets/algorand.ts: -------------------------------------------------------------------------------- 1 | import type { LoginInfoMap } from '../types.js'; 2 | import type { Result } from '@paima/utils'; 3 | import { PaimaMiddlewareErrorCode, buildEndpointErrorFxn } from '../errors.js'; 4 | import { AlgorandConnector } from '@paima/providers'; 5 | import type { ApiForMode, IProvider, WalletMode } from '@paima/providers'; 6 | import { getGameName } from '../state.js'; 7 | import { connectInjected } from './wallet-modes.js'; 8 | 9 | export async function algorandLoginWrapper( 10 | loginInfo: LoginInfoMap[WalletMode.Algorand] 11 | ): Promise>>> { 12 | const errorFxn = buildEndpointErrorFxn('algorandLoginWrapper'); 13 | 14 | const gameInfo = { 15 | gameName: getGameName(), 16 | gameChainId: undefined, // Not needed because of batcher 17 | }; 18 | const loginResult = await connectInjected( 19 | 'algorandLoginWrapper', 20 | errorFxn, 21 | PaimaMiddlewareErrorCode.ALGORAND_LOGIN, 22 | loginInfo, 23 | AlgorandConnector.instance(), 24 | gameInfo 25 | ); 26 | if (loginResult.success === false) { 27 | return loginResult; 28 | } 29 | return { 30 | success: true, 31 | result: loginResult.result, 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/src/wallets/mina.ts: -------------------------------------------------------------------------------- 1 | import type { LoginInfoMap } from '../types.js'; 2 | import { PaimaMiddlewareErrorCode, buildEndpointErrorFxn } from '../errors.js'; 3 | import { MinaConnector } from '@paima/providers'; 4 | import type { ApiForMode, IProvider, WalletMode } from '@paima/providers'; 5 | import { getGameName } from '../state.js'; 6 | import { connectInjected } from './wallet-modes.js'; 7 | import type { Result } from '@paima/utils'; 8 | 9 | export async function minaLoginWrapper( 10 | loginInfo: LoginInfoMap[WalletMode.Mina] 11 | ): Promise>>> { 12 | const errorFxn = buildEndpointErrorFxn('minaLoginWrapper'); 13 | 14 | const gameInfo = { 15 | gameName: getGameName(), 16 | gameChainId: undefined, // Not needed because of batcher 17 | }; 18 | const loginResult = await connectInjected( 19 | 'minaLoginWrapper', 20 | errorFxn, 21 | PaimaMiddlewareErrorCode.MINA_LOGIN, 22 | loginInfo, 23 | MinaConnector.instance(), 24 | gameInfo 25 | ); 26 | if (loginResult.success === false) { 27 | return loginResult; 28 | } 29 | return { 30 | success: true, 31 | result: loginResult.result, 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"], 8 | "references": [ 9 | { "path": "../paima-utils/tsconfig.build.json" }, 10 | { "path": "../paima-prando" }, 11 | { "path": "../paima-concise/tsconfig.build.json" }, 12 | { "path": "../paima-providers/tsconfig.build.json" }, 13 | { "path": "../paima-chain-types/tsconfig.build.json" }, 14 | { "path": "../../node-sdk/paima-rest/tsconfig.build.json" } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/.gitignore: -------------------------------------------------------------------------------- 1 | middleware.js 2 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/bg-green-oval-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/packages/paima-sdk/paima-mw-core/web/TemplateData/bg-green-oval-up.png -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/bg-green-oval-up.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eaf0dc34b4d809cfa927ff3a295f6cc4 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/catapult_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/packages/paima-sdk/paima-mw-core/web/TemplateData/catapult_background.png -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/catapult_background.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd33d576ea01fdf1da8dee7472fdffc3 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/packages/paima-sdk/paima-mw-core/web/TemplateData/favicon.ico -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/favicon.ico.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d860cd9d3c30e7f46bf79d2aca40b3ca 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/fullscreen.svg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 880f2b2b01cdf055ca941146e64a5d6a 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/paima-loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/packages/paima-sdk/paima-mw-core/web/TemplateData/paima-loading.gif -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/paima-loading.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cc188b74b0e1dbd40836a97554b9b3ac 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/paima-logo.svg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8636c388b59208adb1f4b641dbd94d4 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/progress-bar-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/packages/paima-sdk/paima-mw-core/web/TemplateData/progress-bar-empty.png -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/progress-bar-empty.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a97f23c1c90982548867ec2e3d33f8f 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/progress-bar-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaimaStudios/paima-engine/0b70d63a217676ce52748a2cd267f5cbed1109e4/packages/paima-sdk/paima-mw-core/web/TemplateData/progress-bar-full.png -------------------------------------------------------------------------------- /packages/paima-sdk/paima-mw-core/web/TemplateData/progress-bar-full.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd999a04807547a5a83b4cd414d6fbc2 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-prando/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ -------------------------------------------------------------------------------- /packages/paima-sdk/paima-prando/README.md: -------------------------------------------------------------------------------- 1 | # Paima Prando 2 | 3 | Utilities related to randomness generation & usage. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-prando/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/prando", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Fork of Prando for generating randomness for Paima Engine", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc" 24 | }, 25 | "devDependencies": { 26 | "typescript": "^5.5.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-prando/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build" 6 | }, 7 | "include": ["src/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-precompiles/README.md: -------------------------------------------------------------------------------- 1 | # Paima precompiles tooling 2 | 3 | ## About 4 | 5 | Exposes the tools used to generate precompiles needed for a particular game. 6 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-precompiles/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/precompiles", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Library for Paima precompiles helper functions", 8 | "main": "build/index.js", 9 | "types": "build/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "/build" 13 | ], 14 | "author": "Paima Studios", 15 | "license": "See license file", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 19 | }, 20 | "homepage": "https://docs.paimastudios.com", 21 | "scripts": { 22 | "lint:eslint": "eslint .", 23 | "build": "tsc --build tsconfig.build.json" 24 | }, 25 | "dependencies": { 26 | "js-sha3": "^0.9.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-precompiles/src/index.ts: -------------------------------------------------------------------------------- 1 | import sha3 from 'js-sha3'; 2 | const { keccak_256 } = sha3; 3 | 4 | export function generatePrecompile(name: T): `0x${string}` { 5 | // trim to 20 bytes to have evm-sized addresses 6 | const hash = keccak_256(name).slice(0, 40); 7 | 8 | return `0x${hash}`; 9 | } 10 | 11 | type EnumToPrecompile> = { 12 | [K in keyof T as T[K]]: `0x${string}`; 13 | }; 14 | 15 | export function generatePrecompiles>( 16 | names: T 17 | ): EnumToPrecompile { 18 | if (names == null) return {} as EnumToPrecompile; // this happens if you have an empty enum like `enum PrecompileNames {}` 19 | 20 | const result: Record = {}; 21 | for (const val of Object.values(names)) { 22 | result[val] = generatePrecompile(val); 23 | } 24 | return result as EnumToPrecompile; 25 | } 26 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-precompiles/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-precompiles/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["src/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ 5 | src/contract-types/ -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/README.md: -------------------------------------------------------------------------------- 1 | # Paima Providers 2 | 3 | A library to handle the dApp connection interface of various blockchains for the Paima ecosystem. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class WalletNotFound extends Error { 2 | constructor(message?: string) { 3 | super(message); 4 | this.name = 'WalletNotFound'; 5 | } 6 | } 7 | export class UnsupportedWallet extends Error { 8 | constructor(message?: string) { 9 | super(message); 10 | this.name = 'UnsupportedWallet'; 11 | } 12 | } 13 | export class ProviderNotInitialized extends Error { 14 | constructor(message?: string) { 15 | super(message); 16 | this.name = 'ProviderNotInitialized'; 17 | } 18 | } 19 | export class ProviderApiError extends Error { 20 | public code: number | undefined; 21 | 22 | constructor(message?: string, code?: number) { 23 | super(message); 24 | this.name = 'ProviderApiError'; 25 | if (code) { 26 | this.code = code; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/src/evm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './injected.js'; 2 | export * from './ethers.js'; 3 | export type * from './types.js'; 4 | export type * from './injected.js'; 5 | export type * from './ethers.js'; 6 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/src/evm/types.ts: -------------------------------------------------------------------------------- 1 | export type EvmAddress = string; 2 | export const DEFAULT_GAS_LIMIT = 100000; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './algorand.js'; 2 | export * from './cardano.js'; 3 | export * from './evm/index.js'; 4 | export * from './polkadot.js'; 5 | export * from './mina.js'; 6 | export * from './errors.js'; 7 | export * from './utils.js'; 8 | export * from './avail.js'; 9 | export type * from './algorand.js'; 10 | export type * from './cardano.js'; 11 | export type * from './evm/index.js'; 12 | export type * from './polkadot.js'; 13 | export type * from './mina.js'; 14 | export type * from './IProvider.js'; 15 | export type * from './utils.js'; 16 | export type * from './avail.js'; 17 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/src/window.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Paima might be used in non-browser environments where window isn't defined 3 | */ 4 | export function getWindow(): (Window & typeof globalThis) | undefined { 5 | // recall: this is different semantically to window?.foo 6 | // since window?.foo can still give ReferenceError: window is not defined 7 | return typeof window === 'undefined' ? undefined : window; 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | 3 | describe('Test if parsed', () => { 4 | test(`placeholder`, async () => { 5 | expect(false).toEqual(false); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-providers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["test/**/*", "src/**/*"], 8 | "references": [ 9 | { "path": "../paima-crypto/tsconfig.build.json" }, 10 | { "path": "../paima-utils/tsconfig.build.json" }, 11 | { "path": "../paima-chain-types/tsconfig.build.json" }, 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/README.md: -------------------------------------------------------------------------------- 1 | # Paima SDK 2 | 3 | SDK for Paima Engine. This package wraps all other core packages of the Paima SDK, allowing to easily get access to all Paima features with a single dependency. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). 6 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/sdk", 3 | "version": "5.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "SDK for Paima Engine", 8 | "type": "module", 9 | "author": "Paima Studios", 10 | "license": "See license file", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/PaimaStudios/paima-engine.git" 14 | }, 15 | "homepage": "https://docs.paimastudios.com", 16 | "keywords": [ 17 | "autonomous worlds", 18 | "focg", 19 | "onchain game", 20 | "paima" 21 | ], 22 | "scripts": { 23 | "build:copy": "cp package.json ./build/ && cp README.md ./build/", 24 | "build": "npx tsc --build tsconfig.json && npm run build:copy" 25 | }, 26 | "devDependencies": {}, 27 | "dependencies": { 28 | "@paima/chain-types": "5.0.0", 29 | "@paima/config": "5.0.0", 30 | "@paima/concise": "5.0.0", 31 | "@paima/crypto": "5.0.0", 32 | "@paima/executors": "5.0.0", 33 | "@paima/mw-core": "5.0.0", 34 | "@paima/prando": "5.0.0", 35 | "@paima/precompiles": "5.0.0", 36 | "@paima/providers": "5.0.0", 37 | "@paima/utils": "5.0.0", 38 | "@paima/events": "5.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paima/sdk", 3 | "targets": { 4 | "nx-release-publish": { 5 | "dependsOn": ["^nx-release-publish"], 6 | "executor": "@nx/js:release-publish", 7 | "options": { 8 | "packageRoot": "{projectRoot}/build/" 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/chain-types.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/chain-types'; 2 | export type * from '@paima/chain-types'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/concise.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/concise'; 2 | export type * from '@paima/concise'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/config.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/config'; 2 | export type * from '@paima/config'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/crypto.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/crypto'; 2 | export type * from '@paima/crypto'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/events.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/events'; 2 | export type * from '@paima/events'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/executors.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/executors'; 2 | export type * from '@paima/executors'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/mw-core.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/mw-core'; 2 | export type * from '@paima/mw-core'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/prando.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/prando'; 2 | // default types are not included automatically in export * 3 | export { default } from '@paima/prando'; 4 | export type * from '@paima/prando'; 5 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/precompiles.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/precompiles'; 2 | export type * from '@paima/precompiles'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/providers.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/providers'; 2 | export type * from '@paima/providers'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/src/utils.ts: -------------------------------------------------------------------------------- 1 | export * from '@paima/utils'; 2 | export type * from '@paima/utils'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ], 12 | "files": [], 13 | "references": [ 14 | { "path": "../paima-prando" }, 15 | { "path": "../paima-utils/tsconfig.build.json" }, 16 | { "path": "../paima-crypto/tsconfig.build.json" }, 17 | { "path": "../paima-providers/tsconfig.build.json" }, 18 | { "path": "../paima-concise/tsconfig.build.json" }, 19 | { "path": "../paima-config/tsconfig.build.json" }, 20 | { "path": "../paima-executors" }, 21 | { "path": "../paima-mw-core" }, 22 | { "path": "../paima-events/tsconfig.build.json" }, 23 | { "path": "../paima-precompiles/tsconfig.build.json" }, 24 | { "path": "../paima-chain-types/tsconfig.build.json" }, 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | *.tsbuildinfo 4 | cache/ 5 | src/contract-types/ -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/README.md: -------------------------------------------------------------------------------- 1 | # Paima Utils 2 | 3 | A simple library containing helper functions for other Paima libraries. 4 | 5 | You can find the full docs for Paima [here](https://docs.paimastudios.com/). \ 6 | **Note**: We generally recommend using [@paima/sdk](https://www.npmjs.com/package/@paima/sdk) instead of this SDK to get all Paima features as a single package. 7 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/artifacts/ERC165Contract.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "ERC165", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "bytes4", 8 | "name": "interfaceId", 9 | "type": "bytes4" 10 | } 11 | ], 12 | "name": "supportsInterface", 13 | "outputs": [ 14 | { 15 | "internalType": "bool", 16 | "name": "", 17 | "type": "bool" 18 | } 19 | ], 20 | "stateMutability": "view", 21 | "type": "function" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/artifacts/ERC165Contract.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | contractName: 'ERC165', 3 | abi: [ 4 | { 5 | inputs: [ 6 | { 7 | internalType: 'bytes4', 8 | name: 'interfaceId', 9 | type: 'bytes4', 10 | }, 11 | ], 12 | name: 'supportsInterface', 13 | outputs: [ 14 | { 15 | internalType: 'bool', 16 | name: '', 17 | type: 'bool', 18 | }, 19 | ], 20 | stateMutability: 'view', 21 | type: 'function', 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/captcha.ts: -------------------------------------------------------------------------------- 1 | import { ENV } from './config.js'; 2 | /** 3 | * This method will dynamically add: 4 | * 5 | * 6 | * You can manually add this script to your HTML, 7 | * this method is just a helper to do it programmatically. 8 | */ 9 | export async function injectReCaptchaToHTML(): Promise { 10 | const reCAPTCHA_site_key = ENV.RECAPTCHA_V3_FRONTEND; 11 | const url = `https://www.google.com/recaptcha/api.js?render=${reCAPTCHA_site_key}`; 12 | return await new Promise((resolve, reject) => { 13 | const el = document.createElement('script'); 14 | el.src = url; 15 | el.addEventListener('load', () => resolve()); 16 | el.addEventListener('error', () => reject()); 17 | document.body.append(el); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/logging.ts: -------------------------------------------------------------------------------- 1 | import { stringify } from 'flatted'; 2 | 3 | export function logError(error: unknown): void { 4 | doLog(`***ERROR***`); 5 | doLog(error); 6 | doLog(`***`); 7 | } 8 | 9 | type LoggerFunc = (str: string) => void; 10 | 11 | class LoggerHolder { 12 | static INSTANCE = new LoggerHolder(); 13 | log: LoggerFunc = _s => {}; 14 | } 15 | 16 | export function setLogger(newLogger: LoggerFunc): void { 17 | LoggerHolder.INSTANCE.log = newLogger; 18 | } 19 | 20 | // TODO: probably we want to unify this with pushLog 21 | export function doLog(...s: unknown[]): void { 22 | console.log(...s); 23 | for (const str of s) { 24 | if (typeof str !== 'object') { 25 | if (typeof str === 'function') { 26 | continue; 27 | } 28 | LoggerHolder.INSTANCE.log(String(str)); 29 | } else if (str instanceof Error) { 30 | LoggerHolder.INSTANCE.log(`${str.name}: ${str.message}\nStack: ${str.stack}`); 31 | } else { 32 | try { 33 | LoggerHolder.INSTANCE.log(stringify(str)); 34 | } catch (e) { 35 | // should not happen, but maybe there is some type that fails for some reason 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type * from './misc.js'; 2 | export type * from './json-query.js'; 3 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/types/json-query.ts: -------------------------------------------------------------------------------- 1 | export type ErrorCode = number; 2 | export type ErrorMessageMapping = Record; 3 | 4 | export type ErrorMessageFxn = (errorCode: ErrorCode) => string; 5 | 6 | export interface SuccessfulResultMessage { 7 | success: true; 8 | message: string; 9 | } 10 | 11 | export interface SuccessfulResult { 12 | success: true; 13 | result: T; 14 | } 15 | 16 | export interface FailedResult { 17 | success: false; 18 | errorMessage: string; 19 | errorCode?: number; 20 | } 21 | 22 | export type Result = SuccessfulResult | FailedResult; 23 | 24 | // TODO: delete this 25 | export type OldResult = SuccessfulResultMessage | FailedResult; 26 | 27 | export type InternalServerErrorResult = FailedResult; 28 | 29 | /** comes from the `tsoa` package, but we don't want it as a dependency just for this type */ 30 | export interface FieldErrors { 31 | [name: string]: { 32 | message: string; 33 | value?: any; 34 | }; 35 | } 36 | export interface ValidateErrorResult { 37 | message: 'Validation Failed'; 38 | details?: FieldErrors; 39 | } 40 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/src/types/misc.ts: -------------------------------------------------------------------------------- 1 | export type Hash = string; 2 | export type URI = string; 3 | export type UserSignature = string; 4 | 5 | export type VersionString = `${number}.${number}.${number}`; 6 | 7 | export type TransactionTemplate = { 8 | data: string; 9 | to: string; 10 | gasPrice: string; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/test/security/config.yml: -------------------------------------------------------------------------------- 1 | namespace: 2 | write: "CONTRACT_ADDRESS" 3 | read: 4 | # Settings for block height >=10000 5 | - block_height: 10000 6 | prefix: 7 | - "CONTRACT_ADDRESS" # Paima will replace this with your contract's address 8 | - "company_name" 9 | 10 | # Settings for block height >=15000 11 | - block_height: 15000 12 | prefix: 13 | - "new_company_name" -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "build", 6 | "resolveJsonModule": true 7 | }, 8 | "include": [ 9 | "src/**/*", 10 | "src/**/*.json" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/paima-sdk/paima-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "noEmit": true, 6 | }, 7 | "include": ["test/**/*", "src/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/paima-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | } 4 | -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "@paima/source", 4 | "$schema": "node_modules/nx/schemas/project-schema.json", 5 | "targets": { 6 | "prebuild": { 7 | "executor": "nx:noop" 8 | }, 9 | "build": { 10 | "executor": "nx:noop" 11 | }, 12 | "test": { 13 | "executor": "nx:noop" 14 | }, 15 | "lint:eslint": { 16 | "executor": "nx:noop" 17 | }, 18 | "release": { 19 | "executor": "nx:noop" 20 | }, 21 | "local-registry": { 22 | "executor": "@nx/js:verdaccio", 23 | "options": { 24 | "port": 4873, 25 | "config": ".verdaccio/config.yml", 26 | "storage": "bin/npm/tmp/local-registry/storage", 27 | "scopes": ["@paima"] 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /tools/scripts/bump-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | read -p "Enter version number: " version 4 | npx nx release version $version -g paima-sdk 5 | npx nx release version $version -g node-sdk 6 | -------------------------------------------------------------------------------- /tools/scripts/unpack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Install the required pkg-dev-prebuilts and cache it on the user's machine 4 | 5 | # uncompress linux/macos 20.11.0 debug node builds 6 | FILE=$HOME/.pkg-cache/v3.4/built-v20.11.0-linux-x64 7 | if test -f "$FILE"; then 8 | echo "binary $FILE exists, skipping instalation." 9 | else 10 | 11 | # build was split into chunks of 10MBs 12 | curl -LJO https://raw.githubusercontent.com/PaimaStudios/pkg-dev-prebuilts/main/dev-pkg-builtaa 13 | curl -LJO https://raw.githubusercontent.com/PaimaStudios/pkg-dev-prebuilts/main/dev-pkg-builtab 14 | curl -LJO https://raw.githubusercontent.com/PaimaStudios/pkg-dev-prebuilts/main/dev-pkg-builtac 15 | curl -LJO https://raw.githubusercontent.com/PaimaStudios/pkg-dev-prebuilts/main/dev-pkg-builtad 16 | curl -LJO https://raw.githubusercontent.com/PaimaStudios/pkg-dev-prebuilts/main/dev-pkg-builtae 17 | curl -LJO https://raw.githubusercontent.com/PaimaStudios/pkg-dev-prebuilts/main/dev-pkg-builtaf 18 | 19 | cat dev-pkg-built* > debug-builds.tar.gz 20 | 21 | tar -zxvf debug-builds.tar.gz 22 | 23 | mkdir -p $HOME/.pkg-cache/v3.4/ 24 | 25 | rm debug-builds.tar.gz dev-pkg-builta* 26 | 27 | mv built-v20.11.0-* $HOME/.pkg-cache/v3.4/ 28 | fi 29 | -------------------------------------------------------------------------------- /wipe.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | npx nx reset # note: has to run before node_modules deletion 4 | find packages -maxdepth 3 -name 'tsconfig.tsbuildinfo' -type f -exec rm -f {} + 5 | find packages -maxdepth 3 -name 'tsconfig.*.tsbuildinfo' -type f -exec rm -f {} + 6 | find packages -maxdepth 3 -name 'build' -type d -prune -exec rm -rf {} + 7 | 8 | # don't remove just the package-lock because of https://github.com/npm/cli/issues/6301 9 | # if [[ "$1" == "remove-package-lock" ]]; then 10 | # rm -f package-lock.json */package-lock.json 11 | # elif [[ "$1" == "remove-modules" ]]; then 12 | if [[ "$1" == "remove-modules" ]]; then 13 | rm -f package-lock.json 14 | find packages -maxdepth 3 -name 'package-lock.json' -type f -exec rm -f {} + 15 | rm -rf node_modules 16 | find packages -maxdepth 3 -name 'node_modules' -type d -prune -exec rm -rf '{}' + 17 | fi 18 | --------------------------------------------------------------------------------