@clawhub-element-som-ff50647983
Use when the user mentions Element plus drops, NFT creation, NFT collection launch, mint setup, sale stages, prereveal media, preview media, or publishing/pa...
---
name: element-drop
description: Use when the user mentions Element plus drops, NFT creation, NFT collection launch, mint setup, sale stages, prereveal media, preview media, or publishing/pausing/resuming a drop. Also use when they want to create an NFT on Element, create an Element collection/drop, configure mint price/supply/payment token/stages, preview current drop settings/design, update drop media or description, publish a configured drop, or provide chainName, slug, contractAddress, paymentToken, or a local image path for drop work. Read-only preview/list actions may run immediately; every state-changing flow must show an execution preview first, clearly distinguish preview from real execution, then wait for confirmation.
requires: ["node", "jq"]
metadata: {"openclaw":{"requires":{"bins":["node","npm"],"env":["ELEMENT_WALLET_PRIVATE_KEY"]},"primaryEnv":"ELEMENT_WALLET_PRIVATE_KEY"}}
---
# Element Drop
Use this skill for Element Drop lifecycle work: create a drop, preview current configuration, update settings or design, publish a configured drop, resume a paused drop, or pause a live drop.
This skill is not for marketplace trading, collection analytics, wallet portfolio inspection, or generic Element protocol research.
Run the bundled lifecycle commands under `scripts/`; do not default to ad-hoc API calls.
## Runtime Setup
Required environment variable:
- `ELEMENT_WALLET_PRIVATE_KEY`
Example:
```bash
export ELEMENT_WALLET_PRIVATE_KEY="your_wallet_private_key_here"
```
The private key must only be provided through `ELEMENT_WALLET_PRIVATE_KEY`; do not paste it into chat, JSON payloads, files for this skill, or command arguments. The scripts validate it as a `0x`-prefixed 32-byte hex key, use it only for local message and transaction signing, and redact the configured key from known error output. The raw private key is never sent over the network. The scripts may upload media, call Element APIs, and broadcast signed transactions after confirmation, so use a dedicated low-risk wallet.
Only upload user-provided NFT media images. Do not upload secrets, keys, dotfiles, shell configs, environment files, source archives, or arbitrary local documents. The bundled scripts validate uploads as regular local image files and reject symlinks, unsupported extensions, oversized files, and files whose bytes do not match the declared image type.
## Routing Contract
First classify the task, then read the matching reference before you answer with field guidance, collect parameters, or run commands:
- `Create`: new Element NFT collection/drop, stopping before publish
- `List`: show current drops and their `name` / `slug`
- `Preview`: inspect existing settings, design, prereveal media, or public availability
- `Update`: change settings, prereveal image, design fields, design media, or stages
- `Publish`: publish, resume a paused drop, or pause a live drop
- `List chains`: inspect supported chains or payment tokens
- Create: [references/create.md](./references/create.md)
- List: [references/list.md](./references/list.md)
- Preview: [references/preview.md](./references/preview.md)
- Update: [references/update.md](./references/update.md)
- Publish: [references/publish.md](./references/publish.md)
Do not guess supported chains, supported payment tokens, lifecycle defaults, or field constraints from memory. If the user is doing a relevant operation and asks or implies uncertainty about those values, read the matching reference first, then use the read-only command when live data is needed.
Do not use this skill for buying, selling, bidding, canceling, floor price, volume, rankings, activity history, inventory, or portfolio queries.
If the user asks about field meaning or code behavior in the context of Element Drop lifecycle work, this skill may be used for explanation, but do not run lifecycle commands unless the user is actually performing a lifecycle action.
## Confirmation Rules
Read-only commands run immediately:
- `list-user-drops`
- `preview-drop`
- `list-chains`
State-changing commands require preview first:
- `create-drop`
- `update-drop`
- `publish-drop`
For any state-changing command:
1. Gather the minimum required parameters for the lifecycle stage.
2. Run preview mode first.
3. Show a concise execution preview using business language.
4. Wait for explicit positive confirmation.
5. Execute only after confirmation.
If execution includes an onchain transaction, also state that continuing will send a real blockchain transaction, identify the user-visible action that sends it, and make clear that preview mode does not broadcast.
Every preview, execution confirmation, and failure report must repeat the selected chain. For create/deploy flows, also repeat the contract `symbol`. Never silently switch chains after an RPC or network problem; if the requested chain fails, report that chain and ask for a new explicit user instruction before using another chain.
## User-Facing Parameters
General:
- Use `chainName`; do not ask users for chain IDs.
- Use `slug` as the main identifier for existing drops.
- Resolve backend identifiers internally.
- Do not ask for hidden backend IDs when `slug` is enough.
- Local media paths must be absolute.
- Local media paths must point to real image files (`.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`); never use paths to credentials or system files.
- `paymentToken` accepts token name, symbol, or address.
Settings:
- `edition`: `limited` or `open`
- `maxSupply`: required when switching to limited edition
- `dropBeginTime`: mint start time
- `paymentToken`: sale currency
- `stages`: full mint stage array replacement when provided
- `preReveal`: pre-reveal image path
Design:
- `previewMedia`: design preview image path array
- `name`
- `description` / `desc`
- `website`: must be a complete URL
- `twitter`, `instagram`, `discord`, `telegram`, `medium`: users may provide suffix or full link; send suffix to backend
- `bannerFilePath`
- `dropFeaturedImage`
Do not expose backend-only identifiers, status flags, or compatibility storage names in user-facing summaries. Use business language such as chain, slug, live/paused/draft, prereveal image, preview images, and availability.
## Lifecycle Rules
Create:
- Required: `chainName`, `name`, `symbol`, `preReveal`.
- When a create request starts, proactively state these required fields, ask for any that are missing, and then state the defaults that will be applied if the user does not override them.
- Optional overrides include settings, stages, design media, design copy, website/social links, and payment token.
- Default mint start time is the next day.
- Default edition is limited edition with total supply `999`.
- Default preview image is the same image as `preReveal`.
- Default stage is one public stage with sale price `0`, duration `3 days`, phase supply equal to the collection supply, max `1` mint per wallet, no interval, and public mode.
- Create deploys and configures the drop but does not publish by default.
- After create succeeds, tell the user the drop is configured but not live yet, then guide them to preview publishing the same `chainName` + `slug` before confirmed publish execution.
Update:
- Required: `chainName`, `slug`.
- Patch semantics: only explicitly provided fields change; omitted fields keep remote values.
- If `stages` is provided, it replaces the full stage array.
- Stage IDs are not user-controlled.
- Updating settings or prereveal on a live drop requires republish and therefore an onchain confirmation.
- Updating a paused drop, design-only fields, design media, or collection profile fields does not force republish.
Publish:
- Required: `chainName`, `slug`.
- Covers first publish, resuming a paused drop, and pausing a live drop.
- Default target is live.
- If the user asks to keep it paused or pause a live drop, use the paused publish target.
- Publish requires an existing configured prereveal image. The publish flow prepares that image for the live drop configuration automatically; if readiness times out, tell the user to re-upload the prereveal image and retry.
## Web-Only Features
Element Drop supports these features, but this skill does not currently configure them:
- Whitelist stage configuration
- Design detail sections
For those, use the web editor and replace `your-slug` with the actual drop slug:
- [https://element.market/collections/your-slug/edit/drop](https://element.market/collections/your-slug/edit/drop)
## Reporting Contract
For previews, clearly label the response as preview-only and say no changes were applied.
For execution, summarize only the user-visible result.
Include the relevant fields for the lifecycle stage:
- Create: chain, symbol, slug, contract address, collection URL, drop URL, edit URL, settings summary, design summary, recommended next publish action
- List: chain, wallet, drop names, slugs, returned count
- Preview: chain, slug, availability state, mint start time, edition, supply, payment token, stages, design/prereveal media status, links
- Update: chain, slug, fields changed, whether republish was needed, updated settings/design summaries, links
- Publish: chain, slug, transaction hash if sent, final availability state, settings summary, links
Use these business labels in user-facing output:
- `draft`, `live`, `paused` for availability
- `limited edition`, `open edition` for edition
- `prereveal image` for prereveal media
- `preview images` for design preview media
- `sale currency` for payment token
## Failure Reporting
Do not say only "failed".
State the failed lifecycle stage, the relevant error or response summary, and the actionable recovery.
If required parameters are missing, state exactly which user-facing parameters are missing.
For upload, API, or onchain failures, identify the segment in business language.
Always repeat the selected chain in the failure message. For create/deploy failures, repeat the symbol too.
## Absolute Do-Nots
- Do not request or echo the private key.
- Do not execute state-changing commands before confirmation.
- Do not interpret "create" as "create and publish" by default.
- Do not overwrite unspecified fields with defaults during `update-drop`.
- Do not show internal script choreography or backend-only identifiers in normal user-facing output.
FILE:references/publish.md
# Publish Stage Reference
## When to Use
- The drop has already been created and configured, and is now ready to publish
- The drop is currently paused and should be switched back to live state
- The drop is already live and should be switched into paused state
## Minimum Required Parameters
- `chainName`
- A user-facing chain name
- Examples: `base`, `arbitrum`, `bsc`
- The script resolves it internally to the corresponding chain configuration
- `slug`
- The user-facing Element drop or collection slug
- The script resolves it internally to the identifiers required by the backend
## Preconditions
- The drop has already been created
- Settings and design have already been configured
- A valid prereveal asset has already been configured on the drop
- Publish uses the configured prereveal image and resolves the publish-ready prereveal URI automatically
- If prereveal readiness times out, ask the user to re-upload the prereveal image and retry
- If the user needs to change the sale currency first, use `update-drop` with `paymentToken` before publishing
- `publish-drop` can be used for first publish, for resuming a paused drop, and for pausing an already live drop
## Optional Behavior
- By default, publish makes the drop live
- If the user explicitly asks to keep the drop paused, the agent uses the internal paused publish mode
- A paused drop can be resumed by running `publish-drop` without paused mode
- An already live drop can be paused by running `publish-drop` in paused mode
## Execution Preview
First enter the installed skill's `scripts` directory:
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts publish-drop --preview /tmp/element-drop-publish.json
```
The preview should be treated as a transaction preview for the publish step:
- It should confirm a prereveal image is configured and can become publish-ready
- It should warn that confirmed execution sends a real onchain publish transaction
- It should show the transaction summary when available
- It should make clear that preview mode does not broadcast the transaction
## Execute
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts publish-drop /tmp/element-drop-publish.json
```
## Example Payload
```json
{
"chainName": "base",
"slug": "ffffff-510bce"
}
```
## Output Focus
- `slug`
- resolved `contractAddress`
- publish transaction hash
- whether platform synchronization completed
- final availability state
- final `dropBeginTime`
- final `edition`
- final `maxSupply`
- final resolved `paymentToken`
- final full stage summary
- final `Drop URL`
- final `Collection URL`
- final `Edit URL`
FILE:references/list.md
# List Stage Reference
## When to Use
- Show the user's current Element Drop list on a supported chain
- Look up existing drop `name` and `slug` values before preview, update, or publish
- Confirm which collections on a chain are actual Element Drops
## Minimum Required Parameters
- `chainName`
- A user-facing chain name
- Examples: `base`, `arbitrum`, `bsc`
- The script resolves it internally to the corresponding chain configuration
## Common Optional Parameters
- `walletAddress`
- Optional override
- If omitted, the script derives the address from `ELEMENT_WALLET_PRIVATE_KEY`
- `first`
- Forward pagination size
- `after`
- Forward pagination cursor
- `last`
- Backward pagination size
- `before`
- Backward pagination cursor
## Run
First enter the installed skill's `scripts` directory:
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts list-user-drops /tmp/element-drop-list.json
```
## Example Payload
```json
{
"chainName": "base"
}
```
## Output Focus
- `drops[].name`
- `drops[].slug`
- `drops[].isVerified`
- `pageInfo`
FILE:references/create.md
# Create Stage Reference
## When to Use
- Create a new Element Drop
- Deploy the contract and complete the initial media, settings, and design setup
- Explicitly stop before publish
## Minimum Required Parameters
When the user starts a create flow, proactively collect these fields first. If any are missing, ask for the missing required fields and state the defaults below before preparing the preview.
- `chainName`
- A user-facing chain name
- Example values: `base`, `bsc`, `arbitrum`
- Do not guess whether a chain is supported
- If the user is unsure, run `list-chains` before continuing
- The script resolves it internally to the corresponding chain configuration
- `name`
- Collection name shown as the contract name onchain
- Usually the project or collection name users will recognize
- This value cannot be changed after the contract is deployed
- `symbol`
- Short onchain identifier for the contract
- Usually an uppercase shorthand, such as `AZUKI` or `BAYC`
- This value cannot be changed after the contract is deployed
- `preReveal`
- Pre-reveal image path
- Must be a local absolute path
- The workflow uploads this prereveal asset during create
- The workflow also uses this image as the default initial design preview media unless explicit design preview assets are provided
If the user is unsure which chains are currently supported, run:
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts list-chains
```
## Create Defaults
If the user does not override these fields, create uses:
- Mint start time: next day
- Edition: limited edition
- Total supply: `999`
- Sale currency: native chain currency
- Stage set: one public stage
- Default stage name: `Public`
- Default stage sale price: `0`
- Default stage duration: `3 days`
- Default phase supply: same as the collection supply
- Default max mints per wallet: `1`
- Default mint interval: `0`
- Default stage mode: public
- Default banner: prereveal image
- Default preview image: same image as `preReveal`, unless `previewMedia` is provided
Do not describe these as facts if you have not read this reference in the current operation.
## Common Optional Parameters
- `previewMedia`
- Optional preview image path or path array
- Must use local absolute path(s)
- If omitted, defaults to the same image as `preReveal`
- The workflow uploads these files and stores them as the preview images
- `bannerFilePath`
- Optional design banner image path
- If omitted, the prereveal image is used as the initial banner
- `description`
- Drop description
- `desc`
- Alias for `description`; accepted for user convenience and normalized before sending to the backend
- `website`
- Collection website URL; must be a complete URL
- `twitter`
- Twitter/X suffix or full link; normalized to suffix before backend write
- `instagram`
- Instagram suffix or full link; normalized to suffix before backend write
- `discord`
- Discord invite suffix or full link; normalized to suffix before backend write
- `telegram`
- Telegram suffix or full link; normalized to suffix before backend write
- `medium`
- Medium suffix or full link; normalized to suffix before backend write
- `dropFeaturedImage`
- Optional featured image URL for the drop design payload
- `paymentToken`
- Sale currency
- Defaults to native chain currency
- Accepts token `name`, `symbol`, or token address
- Do not guess the supported token list; use `list-chains` when the user asks what is supported or provides an ambiguous token
- `edition`
- `limited` = limited edition
- `open` = open edition
- Defaults to `limited`
- Open edition uses the platform default supply behavior automatically
- `maxSupply`
- Total supply cap for the collection
- Defaults to `999` for limited edition
- `dropBeginTime`
- Mint start time
- Unix timestamp in seconds
- If omitted, defaults to the next day
- `stages`
- Stage array
- If provided, it defines the full mint stage set
- If omitted, the default public stage above is used
## Stage Rules
Each stage may include:
- `stageName`
- `price`
- `duration`
- `maxSupplyAtThisStage`
- `maxMintedPerWallet`
- `interval`
- `stageMode`
Notes:
- `stageID` is never user-controlled
- If the user does not provide stages, do not ask for stage fields unless they want custom mint phases
- The script always assigns stage IDs in order:
- first stage `256`
- second stage `257`
- third stage `258`
- and so on
- Element stages also support whitelist mode on web
- This skill does not support configuring whitelist mode
- Design detail sections are web-only
- If any web-only feature is needed, edit it in the web UI instead, replacing `your-slug` with the actual drop slug:
- [https://element.market/collections/your-slug/edit/drop](https://element.market/collections/your-slug/edit/drop)
## Execution Preview
First enter the installed skill's `scripts` directory:
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts create-drop --preview /tmp/element-drop-create.json
```
The preview should be treated as a transaction preview for the deployment step:
- It should repeat the selected chain and symbol
- It should warn that confirmed execution deploys a real onchain contract
- It should show the transaction summary when available
- It should make clear that preview mode does not broadcast anything
## Execute
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts create-drop /tmp/element-drop-create.json
```
## Output Focus
- `slug`
- selected chain
- `symbol`
- resolved `contractAddress`
- `Drop URL`
- `Collection URL`
- `Edit URL`
- settings summary
- design summary
- next step: preview publishing this same chain and slug, then publish only after confirmation
## Example Payload
```json
{
"chainName": "base",
"name": "ffffff",
"symbol": "F",
"paymentToken": "ETH",
"preReveal": "/absolute/path/to/image.png"
}
```
## Recovery Note
If contract deployment succeeds but later setup fails or times out, do not immediately rerun `create-drop`: that may deploy another contract. Preview the new slug, then use `update-drop` to complete missing settings, prereveal, design, or stage configuration.
If deployment or setup fails, repeat the selected chain and symbol in the error summary. Do not switch to another chain unless the user explicitly asks for that chain.
FILE:references/preview.md
# Preview Stage Reference
## When to Use
- Inspect the current drop settings
- Inspect the current design
- Inspect current prereveal media status
## Minimum Required Parameters
- `chainName`
- A user-facing chain name
- Examples: `base`, `arbitrum`, `bsc`
- The script resolves it internally to the corresponding chain configuration
- `slug`
- The user-facing Element drop or collection slug
- The script resolves it internally to the matching `contractAddress`
## Run
First enter the installed skill's `scripts` directory:
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts preview-drop /tmp/element-drop-preview.json
```
## Example Payload
```json
{
"chainName": "base",
"slug": "ffffff-510bce"
}
```
## Output Focus
- `slug`
- resolved `contractAddress`
- availability state: draft, live, or paused
- `dropBeginTime`
- `edition`
- `maxSupply`
- resolved `paymentToken`
- full stage summary for each stage
- whether design exists
- design preview images
- prereveal image status
FILE:references/update.md
# Update Stage Reference
## When to Use
- Update settings on an existing drop
- Update design copy or media
- Adjust mint stages
## Minimum Required Parameters
- `chainName`
- A user-facing chain name
- Examples: `base`, `arbitrum`, `bsc`
- The script resolves it internally to the corresponding chain configuration
- `slug`
- The user-facing Element drop or collection slug
- The script resolves it internally to `contractAddress`
## Patch Semantics
- The script fetches current remote `settings` and `design` first
- It only overwrites fields the user explicitly provides
- Any omitted field keeps its current remote value
- If the current drop is live and the patch changes `settings` or `preReveal`, `update-drop` does not stop at offchain modification
- In that case it forcibly continues into the publish flow after the modification step
- If the current drop is already paused, the same patch stays offchain and does not force republish
- If the patch only changes `design`, design assets, or collection profile fields, no republish is triggered
- The settings- or prereveal-changing case becomes an onchain-affecting flow and must be confirmed as such
## Common Patchable Fields
### Settings
- `preReveal`
- Pre-reveal media absolute path
- `edition`
- `limited` = limited edition
- `open` = open edition
- Switching to open edition uses the platform default supply behavior automatically
- Switching to limited edition requires an explicit `maxSupply`
- `maxSupply`
- Supply cap for limited edition
- `dropBeginTime`
- `paymentToken`
- Accepts token `name`, `symbol`, or token address
- `stages`
### Design
- `previewMedia`
- Design preview image path array
- The workflow uploads each file, then stores the resulting URLs as design preview images
- `name`
- `description`
- `website`
- Must be a complete URL
- `twitter`
- Accepts either suffix or full link; backend payload uses suffix only
- `instagram`
- Accepts either suffix or full link; backend payload uses suffix only
- `discord`
- Accepts either suffix or full link; backend payload uses suffix only
- `telegram`
- Accepts either suffix or full link; backend payload uses suffix only
- `medium`
- Accepts either suffix or full link; backend payload uses suffix only
- `dropFeaturedImage`
### Design Assets
- `bannerFilePath`
- Banner image absolute path
Notes:
- `previewMedia` is the user-facing input field for design preview images
- If `preReveal` is uploaded and `previewMedia` is not explicitly provided, the workflow also uses the uploaded prereveal image as the initial design preview image
- Element stages also support whitelist mode on web
- This skill does not support configuring whitelist mode
- Design detail sections are web-only
- If any web-only feature is needed, edit it in the web UI instead, replacing `your-slug` with the actual drop slug:
- [https://element.market/collections/your-slug/edit/drop](https://element.market/collections/your-slug/edit/drop)
## Stage Rules
- If `stages` is omitted, the current remote stage config is preserved
- If `stages` is provided, it replaces the full current stage array
- `stageID` is never user-controlled
- The script always rewrites stage IDs to `256 + index`
## Execution Preview
First enter the installed skill's `scripts` directory:
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts update-drop --preview /tmp/element-drop-update.json
```
Current preview behavior:
- show the current values that matter for the requested patch
- show the merged result that would be applied
- show whether the update remains offchain or requires republish
- if republish is required, include the onchain transaction preview
## Execute
```bash
cd <skill-directory>/scripts
npx tsx src/cli.ts update-drop /tmp/element-drop-update.json
```
## Output Focus
- `slug`
- resolved `contractAddress`
- fields actually updated
- settings summary, if settings were updated
- design summary, if design was updated
- whether republish was triggered
- `Drop URL`
- `Collection URL`
- `Edit URL`
## Example Payload
```json
{
"chainName": "base",
"slug": "ffffff-510bce",
"maxSupply": 999,
"paymentToken": "WETH",
"description": "updated description"
}
```
## Example Payload With Media Updates
```json
{
"chainName": "base",
"slug": "ffff",
"paymentToken": "0x4200000000000000000000000000000000000006",
"preReveal": "/absolute/path/to/image.png",
"bannerFilePath": "/absolute/path/to/banner.png",
"previewMedia": [
"/absolute/path/to/image.png"
],
"description": "updated description"
}
```
## Payment Token Guidance
- Use `list-chains` if the user needs the currently supported payment token list for a chain
- Prefer token address when there is any ambiguity between display names or symbols
- If `paymentToken` is omitted during `update-drop`, the current remote payment token setting is preserved
FILE:scripts/pnpm-lock.yaml
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
cuimp:
specifier: ^1.10.0
version: 1.10.0
ethers:
specifier: ^6.13.5
version: 6.16.0
zod:
specifier: ^3.24.1
version: 3.25.76
devDependencies:
'@types/node':
specifier: ^24.9.1
version: 24.12.2
tsx:
specifier: ^4.20.6
version: 4.21.0
typescript:
specifier: ^5.9.3
version: 5.9.3
vitest:
specifier: ^3.2.4
version: 3.2.4(@types/[email protected])([email protected])
packages:
'@adraffy/[email protected]':
resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==}
'@esbuild/[email protected]':
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/[email protected]':
resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/[email protected]':
resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/[email protected]':
resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/[email protected]':
resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/[email protected]':
resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/[email protected]':
resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/[email protected]':
resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/[email protected]':
resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/[email protected]':
resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/[email protected]':
resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/[email protected]':
resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/[email protected]':
resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/[email protected]':
resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/[email protected]':
resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/[email protected]':
resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/[email protected]':
resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/[email protected]':
resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@isaacs/[email protected]':
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
engines: {node: '>=18.0.0'}
'@jridgewell/[email protected]':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@noble/[email protected]':
resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
'@noble/[email protected]':
resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==}
engines: {node: '>= 16'}
'@rollup/[email protected]':
resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==}
cpu: [arm]
os: [android]
'@rollup/[email protected]':
resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==}
cpu: [arm64]
os: [android]
'@rollup/[email protected]':
resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==}
cpu: [arm64]
os: [darwin]
'@rollup/[email protected]':
resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==}
cpu: [x64]
os: [darwin]
'@rollup/[email protected]':
resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==}
cpu: [arm64]
os: [freebsd]
'@rollup/[email protected]':
resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==}
cpu: [x64]
os: [freebsd]
'@rollup/[email protected]':
resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/[email protected]':
resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/[email protected]':
resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==}
cpu: [loong64]
os: [linux]
libc: [musl]
'@rollup/[email protected]':
resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==}
cpu: [ppc64]
os: [linux]
libc: [musl]
'@rollup/[email protected]':
resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/[email protected]':
resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/[email protected]':
resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==}
cpu: [x64]
os: [openbsd]
'@rollup/[email protected]':
resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==}
cpu: [arm64]
os: [openharmony]
'@rollup/[email protected]':
resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==}
cpu: [arm64]
os: [win32]
'@rollup/[email protected]':
resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==}
cpu: [ia32]
os: [win32]
'@rollup/[email protected]':
resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==}
cpu: [x64]
os: [win32]
'@rollup/[email protected]':
resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==}
cpu: [x64]
os: [win32]
'@types/[email protected]':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
'@types/[email protected]':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
'@types/[email protected]':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/[email protected]':
resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==}
'@types/[email protected]':
resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==}
'@vitest/[email protected]':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
'@vitest/[email protected]':
resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/[email protected]':
resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
'@vitest/[email protected]':
resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
'@vitest/[email protected]':
resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
'@vitest/[email protected]':
resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
'@vitest/[email protected]':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
[email protected]:
resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==}
[email protected]:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
[email protected]:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
[email protected]:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
[email protected]:
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
engines: {node: '>= 16'}
[email protected]:
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
[email protected]:
resolution: {integrity: sha512-+cIbWHQ+ZQ7Nc3TJoCxqfDl06/ormSN5zV6mV0qcJVzTM2lHLTs/8ujgSJpsbzg6DNKNeHSX6g/HoTDWgCKF3w==}
engines: {node: '>=18.17'}
[email protected]:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
[email protected]:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
[email protected]:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
[email protected]:
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
engines: {node: '>=18'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
[email protected]:
resolution: {integrity: sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==}
engines: {node: '>=14.0.0'}
[email protected]:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
[email protected]:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
[email protected]:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
[email protected]:
resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==}
[email protected]:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
[email protected]:
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
[email protected]:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
[email protected]:
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
engines: {node: '>=16 || 14 >=14.17'}
[email protected]:
resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
engines: {node: '>= 18'}
[email protected]:
resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
engines: {node: '>=10'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
[email protected]:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
[email protected]:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
[email protected]:
resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
engines: {node: '>= 14.16'}
[email protected]:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
[email protected]:
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
[email protected]:
resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
engines: {node: ^10 || ^12 || >=14}
[email protected]:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
[email protected]:
resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
[email protected]:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
[email protected]:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
[email protected]:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
[email protected]:
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
[email protected]:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'}
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting [email protected]
[email protected]:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
[email protected]:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
[email protected]:
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
engines: {node: '>=12.0.0'}
[email protected]:
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
[email protected]:
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
engines: {node: '>=14.0.0'}
[email protected]:
resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==}
engines: {node: '>=14.0.0'}
[email protected]:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
[email protected]:
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
engines: {node: '>=18.0.0'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
[email protected]:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
[email protected]:
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
[email protected]:
resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
'@types/node': ^20.19.0 || >=22.12.0
jiti: '>=1.21.0'
less: ^4.0.0
lightningcss: ^1.21.0
sass: ^1.70.0
sass-embedded: ^1.70.0
stylus: '>=0.54.8'
sugarss: ^5.0.0
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
'@types/node':
optional: true
jiti:
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
tsx:
optional: true
yaml:
optional: true
[email protected]:
resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/debug': ^4.1.12
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
'@vitest/browser': 3.2.4
'@vitest/ui': 3.2.4
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@types/debug':
optional: true
'@types/node':
optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
[email protected]:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
[email protected]:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
[email protected]:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
snapshots:
'@adraffy/[email protected]': {}
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
'@isaacs/[email protected]':
dependencies:
minipass: 7.1.3
'@jridgewell/[email protected]': {}
'@noble/[email protected]':
dependencies:
'@noble/hashes': 1.3.2
'@noble/[email protected]': {}
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@rollup/[email protected]':
optional: true
'@types/[email protected]':
dependencies:
'@types/deep-eql': 4.0.2
assertion-error: 2.0.1
'@types/[email protected]': {}
'@types/[email protected]': {}
'@types/[email protected]':
dependencies:
undici-types: 6.19.8
'@types/[email protected]':
dependencies:
undici-types: 7.16.0
'@vitest/[email protected]':
dependencies:
'@types/chai': 5.2.3
'@vitest/spy': 3.2.4
'@vitest/utils': 3.2.4
chai: 5.3.3
tinyrainbow: 2.0.0
'@vitest/[email protected]([email protected](@types/[email protected])([email protected]))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.2(@types/[email protected])([email protected])
'@vitest/[email protected]':
dependencies:
tinyrainbow: 2.0.0
'@vitest/[email protected]':
dependencies:
'@vitest/utils': 3.2.4
pathe: 2.0.3
strip-literal: 3.1.0
'@vitest/[email protected]':
dependencies:
'@vitest/pretty-format': 3.2.4
magic-string: 0.30.21
pathe: 2.0.3
'@vitest/[email protected]':
dependencies:
tinyspy: 4.0.4
'@vitest/[email protected]':
dependencies:
'@vitest/pretty-format': 3.2.4
loupe: 3.2.1
tinyrainbow: 2.0.0
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.3
deep-eql: 5.0.2
loupe: 3.2.1
pathval: 2.0.1
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
tar: 7.4.3
[email protected]:
dependencies:
ms: 2.1.3
[email protected]: {}
[email protected]: {}
[email protected]:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.7
'@esbuild/android-arm': 0.27.7
'@esbuild/android-arm64': 0.27.7
'@esbuild/android-x64': 0.27.7
'@esbuild/darwin-arm64': 0.27.7
'@esbuild/darwin-x64': 0.27.7
'@esbuild/freebsd-arm64': 0.27.7
'@esbuild/freebsd-x64': 0.27.7
'@esbuild/linux-arm': 0.27.7
'@esbuild/linux-arm64': 0.27.7
'@esbuild/linux-ia32': 0.27.7
'@esbuild/linux-loong64': 0.27.7
'@esbuild/linux-mips64el': 0.27.7
'@esbuild/linux-ppc64': 0.27.7
'@esbuild/linux-riscv64': 0.27.7
'@esbuild/linux-s390x': 0.27.7
'@esbuild/linux-x64': 0.27.7
'@esbuild/netbsd-arm64': 0.27.7
'@esbuild/netbsd-x64': 0.27.7
'@esbuild/openbsd-arm64': 0.27.7
'@esbuild/openbsd-x64': 0.27.7
'@esbuild/openharmony-arm64': 0.27.7
'@esbuild/sunos-x64': 0.27.7
'@esbuild/win32-arm64': 0.27.7
'@esbuild/win32-ia32': 0.27.7
'@esbuild/win32-x64': 0.27.7
[email protected]:
dependencies:
'@types/estree': 1.0.8
[email protected]:
dependencies:
'@adraffy/ens-normalize': 1.10.1
'@noble/curves': 1.2.0
'@noble/hashes': 1.3.2
'@types/node': 22.7.5
aes-js: 4.0.0-beta.5
tslib: 2.7.0
ws: 8.17.1
transitivePeerDependencies:
- bufferutil
- utf-8-validate
[email protected]: {}
[email protected]([email protected]):
optionalDependencies:
picomatch: 4.0.4
[email protected]:
optional: true
[email protected]:
dependencies:
resolve-pkg-maps: 1.0.0
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
[email protected]: {}
[email protected]:
dependencies:
minipass: 7.1.3
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
[email protected]: {}
[email protected]:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.60.1
'@rollup/rollup-android-arm64': 4.60.1
'@rollup/rollup-darwin-arm64': 4.60.1
'@rollup/rollup-darwin-x64': 4.60.1
'@rollup/rollup-freebsd-arm64': 4.60.1
'@rollup/rollup-freebsd-x64': 4.60.1
'@rollup/rollup-linux-arm-gnueabihf': 4.60.1
'@rollup/rollup-linux-arm-musleabihf': 4.60.1
'@rollup/rollup-linux-arm64-gnu': 4.60.1
'@rollup/rollup-linux-arm64-musl': 4.60.1
'@rollup/rollup-linux-loong64-gnu': 4.60.1
'@rollup/rollup-linux-loong64-musl': 4.60.1
'@rollup/rollup-linux-ppc64-gnu': 4.60.1
'@rollup/rollup-linux-ppc64-musl': 4.60.1
'@rollup/rollup-linux-riscv64-gnu': 4.60.1
'@rollup/rollup-linux-riscv64-musl': 4.60.1
'@rollup/rollup-linux-s390x-gnu': 4.60.1
'@rollup/rollup-linux-x64-gnu': 4.60.1
'@rollup/rollup-linux-x64-musl': 4.60.1
'@rollup/rollup-openbsd-x64': 4.60.1
'@rollup/rollup-openharmony-arm64': 4.60.1
'@rollup/rollup-win32-arm64-msvc': 4.60.1
'@rollup/rollup-win32-ia32-msvc': 4.60.1
'@rollup/rollup-win32-x64-gnu': 4.60.1
'@rollup/rollup-win32-x64-msvc': 4.60.1
fsevents: 2.3.3
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
js-tokens: 9.0.1
[email protected]:
dependencies:
'@isaacs/fs-minipass': 4.0.1
chownr: 3.0.0
minipass: 7.1.3
minizlib: 3.1.0
mkdirp: 3.0.1
yallist: 5.0.0
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
fdir: 6.5.0([email protected])
picomatch: 4.0.4
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]:
dependencies:
esbuild: 0.27.7
get-tsconfig: 4.14.0
optionalDependencies:
fsevents: 2.3.3
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected](@types/[email protected])([email protected]):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 7.3.2(@types/[email protected])([email protected])
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
[email protected](@types/[email protected])([email protected]):
dependencies:
esbuild: 0.27.7
fdir: 6.5.0([email protected])
picomatch: 4.0.4
postcss: 8.5.10
rollup: 4.60.1
tinyglobby: 0.2.16
optionalDependencies:
'@types/node': 24.12.2
fsevents: 2.3.3
tsx: 4.21.0
[email protected](@types/[email protected])([email protected]):
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4([email protected](@types/[email protected])([email protected]))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
'@vitest/spy': 3.2.4
'@vitest/utils': 3.2.4
chai: 5.3.3
debug: 4.4.3
expect-type: 1.3.0
magic-string: 0.30.21
pathe: 2.0.3
picomatch: 4.0.4
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.16
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 7.3.2(@types/[email protected])([email protected])
vite-node: 3.2.4(@types/[email protected])([email protected])
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 24.12.2
transitivePeerDependencies:
- jiti
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
[email protected]:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
[email protected]: {}
[email protected]: {}
[email protected]: {}
FILE:scripts/package.json
{
"name": "element-drop-scripts",
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
"check": "pnpm run typecheck",
"test": "vitest run",
"dev": "tsx src/cli.ts"
},
"dependencies": {
"cuimp": "^1.10.0",
"ethers": "^6.13.5",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/node": "^24.9.1",
"tsx": "^4.20.6",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
}
}
FILE:scripts/tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"lib": ["ES2022", "DOM"],
"types": ["node", "vitest/globals"],
"outDir": "dist"
},
"include": ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"]
}
FILE:scripts/vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "node",
restoreMocks: true
}
});
FILE:scripts/src/schema.ts
import { z } from "zod";
import type { CreateDropInput, CreateStageInput, DropInput, StageInput } from "./types";
import { DEFAULT_MAX_SUPPLY, resolveDropMode } from "./drop-mode";
const DEFAULT_STAGE_DURATION_SECONDS = 3 * 24 * 60 * 60;
const DEFAULT_STAGE_NAME = "Public";
const DEFAULT_STAGE_PRICE = "0";
const DEFAULT_STAGE_INTERVAL = 0;
const DEFAULT_STAGE_MAX_MINTED_PER_WALLET = 1;
const DEFAULT_STAGE_ID = 256;
const stageSchema = z.object({
stageID: z.number().int().nonnegative(),
stageName: z.string().min(1),
price: z.string().min(1),
duration: z.number().int().positive(),
maxSupplyAtThisStage: z.number().int().positive(),
maxMintedPerWallet: z.number().int().positive(),
interval: z.number().int().nonnegative(),
stageMode: z.union([z.literal(0), z.literal(1)])
});
const createStageSchema = z.object({
stageID: z.number().int().nonnegative().optional(),
stageName: z.string().min(1),
price: z.string().min(1),
duration: z.number().int().positive(),
maxSupplyAtThisStage: z.number().int().positive(),
maxMintedPerWallet: z.number().int().positive(),
interval: z.number().int().nonnegative(),
stageMode: z.union([z.literal(0), z.literal(1)])
});
const createDropInputSchema = z.object({
chainMId: z.number().int().positive(),
name: z.string().min(1),
symbol: z.string().min(1),
paymentToken: z.string().min(1).optional(),
preReveal: z.string().min(1).optional(),
previewMedia: z.array(z.string().min(1)).optional(),
description: z.string().optional(),
desc: z.string().optional(),
website: z.string().optional(),
twitter: z.string().optional(),
instagram: z.string().optional(),
discord: z.string().optional(),
telegram: z.string().optional(),
medium: z.string().optional(),
dropFeaturedImage: z.string().optional(),
edition: z.union([z.literal("limited"), z.literal("open")]).optional(),
dropType: z.union([z.literal(0), z.literal(1)]).optional(),
maxSupply: z.number().int().positive().optional(),
dropBeginTime: z.number().int().positive().optional(),
stages: z.array(createStageSchema).min(1).optional()
}).superRefine((input, ctx) => {
if (!input.preReveal) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "preReveal is required",
path: ["preReveal"]
});
}
});
export const dropInputSchema = z
.object({
chainMId: z.number().int().positive(),
name: z.string().min(1),
symbol: z.string().min(1),
paymentToken: z.string().min(1).optional(),
preReveal: z.string().min(1),
description: z.string(),
dropType: z.union([z.literal(0), z.literal(1)]),
maxSupply: z.number().int().positive(),
dropBeginTime: z.number().int().positive(),
stages: z.array(stageSchema).min(1)
})
.superRefine((input, ctx) => {
const stageSupply = input.stages.reduce((sum, stage) => sum + stage.maxSupplyAtThisStage, 0);
if (stageSupply > input.maxSupply) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "stages total maxSupply exceeds drop maxSupply"
});
}
});
function defaultDropBeginTime(): number {
return Math.floor(Date.now() / 1000) + 24 * 60 * 60;
}
function assignStageIds(stages: CreateStageInput[]): StageInput[] {
return stages.map((stage, index) => ({
...stage,
stageID: DEFAULT_STAGE_ID + index
}));
}
function buildDefaultStage(maxSupply: number): StageInput {
return {
stageID: DEFAULT_STAGE_ID,
stageName: DEFAULT_STAGE_NAME,
price: DEFAULT_STAGE_PRICE,
duration: DEFAULT_STAGE_DURATION_SECONDS,
maxSupplyAtThisStage: maxSupply,
maxMintedPerWallet: DEFAULT_STAGE_MAX_MINTED_PER_WALLET,
interval: DEFAULT_STAGE_INTERVAL,
stageMode: 0
};
}
export function normalizeCreateDropInput(input: CreateDropInput): DropInput {
const parsed = createDropInputSchema.parse(input);
const { dropType, maxSupply } = resolveDropMode({
requestedEdition: parsed.edition,
requestedDropType: parsed.dropType,
requestedMaxSupply: parsed.maxSupply,
fallbackMaxSupply: DEFAULT_MAX_SUPPLY
});
const normalized: DropInput = {
chainMId: parsed.chainMId,
name: parsed.name,
symbol: parsed.symbol,
paymentToken: parsed.paymentToken,
preReveal: parsed.preReveal ?? "",
description: parsed.description ?? parsed.desc ?? "",
dropType,
maxSupply,
dropBeginTime: parsed.dropBeginTime ?? defaultDropBeginTime(),
stages: parsed.stages ? assignStageIds(parsed.stages) : [buildDefaultStage(maxSupply)]
};
return dropInputSchema.parse(normalized);
}
export type DropInputSchema = z.infer<typeof dropInputSchema>;
FILE:scripts/src/drop-mode.ts
import type { DropEdition, DropType } from "./types";
export const DEFAULT_DROP_TYPE = 0 as const;
export const DEFAULT_MAX_SUPPLY = 999;
export const OPEN_EDITION_MAX_SUPPLY = 1_000_000_000;
export function deriveEditionFromMaxSupply(maxSupply: unknown): DropEdition | null {
if (typeof maxSupply !== "number" || !Number.isFinite(maxSupply)) {
return null;
}
return maxSupply >= OPEN_EDITION_MAX_SUPPLY ? "open" : "limited";
}
export function resolveMaxSupplyForEdition(input: {
requestedEdition?: DropEdition;
requestedMaxSupply?: number;
fallbackMaxSupply?: number;
}): number {
if (input.requestedEdition === "open") {
return OPEN_EDITION_MAX_SUPPLY;
}
if (input.requestedEdition === "limited" && input.requestedMaxSupply === undefined) {
throw new Error("limited edition requires an explicit maxSupply");
}
return input.requestedMaxSupply ?? input.fallbackMaxSupply ?? DEFAULT_MAX_SUPPLY;
}
export function resolveDropMode(input: {
requestedEdition?: DropEdition;
requestedDropType?: DropType;
requestedMaxSupply?: number;
fallbackDropType?: DropType;
fallbackMaxSupply?: number;
}): { dropType: DropType; maxSupply: number } {
return {
dropType: input.requestedDropType ?? input.fallbackDropType ?? DEFAULT_DROP_TYPE,
maxSupply: resolveMaxSupplyForEdition(input)
};
}
FILE:scripts/src/security/upload-guard.ts
import { lstat, readFile, realpath, stat } from "node:fs/promises";
import { basename, isAbsolute } from "node:path";
const MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
const ALLOWED_IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
export function inferUploadExtension(filePath: string): string {
const name = basename(filePath);
const index = name.lastIndexOf(".");
return index >= 0 ? name.slice(index) : "";
}
export function inferUploadImageMimeType(filePath: string): string {
const extension = inferUploadExtension(filePath).toLowerCase();
switch (extension) {
case ".png":
return "image/png";
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".gif":
return "image/gif";
case ".webp":
return "image/webp";
default:
throw new Error(`Unsupported upload image extension: extension || "(none)"`);
}
}
function isSupportedImageHeader(extension: string, header: Buffer): boolean {
if (extension === ".png") {
return header.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));
}
if (extension === ".jpg" || extension === ".jpeg") {
return header[0] === 0xff && header[1] === 0xd8 && header[2] === 0xff;
}
if (extension === ".gif") {
const signature = header.subarray(0, 6).toString("ascii");
return signature === "GIF87a" || signature === "GIF89a";
}
if (extension === ".webp") {
return header.subarray(0, 4).toString("ascii") === "RIFF" && header.subarray(8, 12).toString("ascii") === "WEBP";
}
return false;
}
export function assertSafeUploadFileName(fileName: string) {
if (fileName !== basename(fileName) || fileName.startsWith(".") || fileName.includes("\0")) {
throw new Error(`Unsafe upload file name: fileName`);
}
}
export async function validateLocalImageUpload(filePath: string): Promise<{ realPath: string; mimeType: string }> {
if (!isAbsolute(filePath)) {
throw new Error(`Upload path must be absolute: filePath`);
}
const linkStats = await lstat(filePath);
if (linkStats.isSymbolicLink()) {
throw new Error(`Upload path must not be a symbolic link: filePath`);
}
if (!linkStats.isFile()) {
throw new Error(`Upload path must be a regular image file: filePath`);
}
if (linkStats.size <= 0 || linkStats.size > MAX_UPLOAD_BYTES) {
throw new Error(`Upload image size must be between 1 byte and MAX_UPLOAD_BYTES bytes: filePath`);
}
const realPath = await realpath(filePath);
const realStats = await stat(realPath);
if (!realStats.isFile()) {
throw new Error(`Upload path must resolve to a regular image file: filePath`);
}
const extension = inferUploadExtension(realPath).toLowerCase();
if (!ALLOWED_IMAGE_EXTENSIONS.has(extension)) {
throw new Error(`Unsupported upload image extension: extension || "(none)"`);
}
const header = await readFile(realPath, { flag: "r" }).then((buffer) => buffer.subarray(0, 12));
if (!isSupportedImageHeader(extension, header)) {
throw new Error(`Upload file does not match supported image signature: filePath`);
}
return {
realPath,
mimeType: inferUploadImageMimeType(realPath)
};
}
export async function readValidatedLocalImageUpload(filePath: string): Promise<{
bytes: ArrayBuffer;
fileName: string;
mimeType: string;
realPath: string;
}> {
const validated = await validateLocalImageUpload(filePath);
const bytes = await readFile(validated.realPath);
return {
...validated,
bytes: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer,
fileName: basename(validated.realPath)
};
}
FILE:scripts/src/auth/jwt.ts
import { Wallet } from "ethers";
import type { ElementIdentity, ElementLoginInput } from "../types";
import { ELEMENT_CHAIN_METADATA_BY_CHAIN_MID } from "../network/chains";
export function getElementBlockChainByChainMId(chainMId: number): { chain: string; chainId: string } {
const chain = ELEMENT_CHAIN_METADATA_BY_CHAIN_MID[chainMId];
if (!chain) {
throw new Error(`Unsupported chainMId for Element login: chainMId`);
}
return {
chain: chain.chain,
chainId: `0xchain.chainId.toString(16)`
};
}
export interface BuildElementAuthorizationDeps {
getLoginNonce: (identity: ElementIdentity) => Promise<string>;
loginAuth: (input: ElementLoginInput) => Promise<string>;
}
export interface ElementAuthorizationResult {
authorization: string;
nonce: string;
message: string;
identity: ElementIdentity;
}
export async function deriveWalletAddress(input: { privateKey: string }): Promise<string> {
const wallet = new Wallet(input.privateKey);
return wallet.address;
}
export function getElementIdentityByChainMId(chainMId: number, walletAddress: string): ElementIdentity {
const blockChain = getElementBlockChainByChainMId(chainMId);
return {
address: walletAddress,
blockChain
};
}
export function buildElementLoginMessage(input: { walletAddress: string; nonce: string }): string {
return `Welcome to Element!\n \nClick "Sign" to sign in. No password needed!\n \nI accept the Element Terms of Service: \n https://element.market/tos\n \nWallet address:\ninput.walletAddress\n \nNonce:\ninput.nonce`;
}
export async function buildElementAuthorization(
deps: BuildElementAuthorizationDeps,
input: {
privateKey: string;
walletAddress?: string;
chainMId: number;
}
): Promise<ElementAuthorizationResult> {
const walletAddress =
(input.walletAddress ?? (await deriveWalletAddress({ privateKey: input.privateKey }))).toLowerCase();
const identity = getElementIdentityByChainMId(input.chainMId, walletAddress);
const nonce = await deps.getLoginNonce(identity);
const message = buildElementLoginMessage({ walletAddress, nonce });
const wallet = new Wallet(input.privateKey);
const signature = await wallet.signMessage(message);
const token = await deps.loginAuth({
identity,
message,
signature
});
return {
authorization: `Bearer token`,
nonce,
message,
identity
};
}
FILE:scripts/src/network/rpc.ts
import { getJson } from "../api/http";
export const RPC_CONF_API_URL = "https://api.element.market/v1/quote/rpcConfInfo";
export interface RpcConfInfo {
chainMId: number;
rpcUrl: string;
isWalletPriority: boolean;
}
interface RpcConfResponse {
code: number;
status: string;
data: RpcConfInfo[];
}
const STATIC_RPC_URLS: Record<number, string> = {
1: "https://api.zan.top/node/v1/eth/mainnet/6e96cfbcaff949bfbdaeb5fbc554ac7c"
};
let cachedRpcConfigs: Map<number, RpcConfInfo> | null = null;
let lastFetchTime = 0;
const CACHE_DURATION_MS = 5 * 60 * 1000;
export async function fetchRpcConfigs(): Promise<RpcConfInfo[]> {
const result = await getJson<RpcConfResponse>(RPC_CONF_API_URL);
if (result.code !== 0) {
throw new Error(`Failed to fetch rpc configs: result.status`);
}
return result.data;
}
export async function getCachedRpcConfigs(): Promise<Map<number, RpcConfInfo>> {
const now = Date.now();
if (cachedRpcConfigs && now - lastFetchTime < CACHE_DURATION_MS) {
return cachedRpcConfigs;
}
const configs = await fetchRpcConfigs();
const filtered = configs.filter((config) => !config.isWalletPriority);
cachedRpcConfigs = new Map(filtered.map((config) => [config.chainMId, config]));
Object.entries(STATIC_RPC_URLS).forEach(([chainMId, rpcUrl]) => {
const numericChainMId = Number(chainMId);
if (!cachedRpcConfigs?.has(numericChainMId)) {
cachedRpcConfigs?.set(numericChainMId, {
chainMId: numericChainMId,
rpcUrl,
isWalletPriority: false
});
}
});
lastFetchTime = now;
return cachedRpcConfigs;
}
export async function getRpcUrlForChainMId(chainMId: number): Promise<string> {
const configs = await getCachedRpcConfigs();
const rpcUrl = configs.get(chainMId)?.rpcUrl;
if (!rpcUrl) {
throw new Error(`Unsupported chainMId for rpc resolution: chainMId`);
}
return rpcUrl;
}
export function __resetRpcConfigCacheForTests(): void {
cachedRpcConfigs = null;
lastFetchTime = 0;
}
FILE:scripts/src/network/transaction.ts
import { Interface, JsonRpcProvider, Wallet } from "ethers";
import { getRequiredWalletPrivateKey } from "../env";
import type { EncodedTransaction, ExecutedTransactionResult } from "../types";
const TOKEN_FACTORY_INTERFACE = new Interface([
"event CreateToken(address indexed tokenAddress, uint8 tokenType, string name, string symbol, address implementation, address protocolRecipient, uint16 protocolPoint)"
]);
function getConfiguredMinPriorityFeePerGasWei(): bigint | undefined {
const configured = process.env.ELEMENT_MIN_PRIORITY_FEE_PER_GAS_WEI;
if (!configured) {
return undefined;
}
const parsed = BigInt(configured);
if (parsed <= 0n) {
throw new Error("ELEMENT_MIN_PRIORITY_FEE_PER_GAS_WEI must be greater than 0");
}
return parsed;
}
export function buildFeeOverrides(input: {
maxFeePerGas?: bigint | null;
maxPriorityFeePerGas?: bigint | null;
gasPrice?: bigint | null;
minPriorityFeePerGas?: bigint;
}) {
const minPriorityFeePerGas = input.minPriorityFeePerGas ?? getConfiguredMinPriorityFeePerGasWei();
if (input.maxFeePerGas !== null && input.maxFeePerGas !== undefined) {
const feeOverrides: { maxFeePerGas: bigint; maxPriorityFeePerGas?: bigint } = {
maxFeePerGas: input.maxFeePerGas
};
const priorityFee =
input.maxPriorityFeePerGas !== null && input.maxPriorityFeePerGas !== undefined
? minPriorityFeePerGas !== undefined && input.maxPriorityFeePerGas < minPriorityFeePerGas
? minPriorityFeePerGas
: input.maxPriorityFeePerGas
: minPriorityFeePerGas;
if (priorityFee !== undefined) {
feeOverrides.maxPriorityFeePerGas = priorityFee;
if (feeOverrides.maxFeePerGas < priorityFee) {
feeOverrides.maxFeePerGas = priorityFee;
}
}
return feeOverrides;
}
if (input.gasPrice !== null && input.gasPrice !== undefined) {
return {
gasPrice:
minPriorityFeePerGas !== undefined && input.gasPrice < minPriorityFeePerGas
? minPriorityFeePerGas
: input.gasPrice
};
}
return minPriorityFeePerGas === undefined
? {}
: {
maxPriorityFeePerGas: minPriorityFeePerGas,
maxFeePerGas: minPriorityFeePerGas
};
}
export function parseMinimumTipCapWei(error: unknown): bigint | null {
const message = error instanceof Error ? error.message : String(error);
const match = message.match(/minimum needed\s+(\d+)/i);
return match ? BigInt(match[1]) : null;
}
export async function sendEncodedTransaction(input: {
rpcUrl: string;
transaction: EncodedTransaction;
waitConfirmations?: number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}): Promise<ExecutedTransactionResult> {
input.logger?.("send transaction:start", {
rpcUrl: input.rpcUrl,
to: input.transaction.to,
value: input.transaction.value,
waitConfirmations: input.waitConfirmations ?? 1
});
const privateKey = getRequiredWalletPrivateKey();
const provider = new JsonRpcProvider(input.rpcUrl);
const wallet = new Wallet(privateKey, provider);
let minPriorityFeePerGas: bigint | undefined;
let response;
for (let attempt = 1; attempt <= 2; attempt += 1) {
const feeData = await provider.getFeeData();
const feeOverrides = buildFeeOverrides({
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
gasPrice: feeData.gasPrice,
minPriorityFeePerGas
});
try {
response = await wallet.sendTransaction({
to: input.transaction.to,
value: input.transaction.value,
data: input.transaction.data,
...feeOverrides
});
break;
} catch (error) {
const minimumTipCapWei = parseMinimumTipCapWei(error);
if (attempt >= 2 || minimumTipCapWei === null) {
throw error;
}
minPriorityFeePerGas = minimumTipCapWei;
input.logger?.("send transaction:retry-min-tip-cap", {
minimumTipCapWei: minimumTipCapWei.toString()
});
}
}
if (!response) {
throw new Error("Transaction response missing after send attempt");
}
const receipt = await response.wait(input.waitConfirmations ?? 1);
if (!receipt) {
throw new Error(`Transaction receipt missing for response.hash`);
}
if (receipt.status !== 1) {
throw new Error(`Transaction failed: response.hash`);
}
let contractAddress: string | undefined;
for (const log of receipt.logs) {
try {
const parsed = TOKEN_FACTORY_INTERFACE.parseLog(log);
if (parsed?.name === "CreateToken") {
contractAddress = String(parsed.args.tokenAddress).toLowerCase();
break;
}
} catch {
// ignore unrelated logs
}
}
input.logger?.("send transaction:confirmed", {
hash: response.hash,
blockNumber: receipt.blockNumber,
contractAddress
});
return {
hash: response.hash,
contractAddress,
receipt: {
hash: receipt.hash,
blockNumber: receipt.blockNumber,
status: receipt.status,
gasUsed: receipt.gasUsed.toString()
}
};
}
FILE:scripts/src/network/chains.ts
import type { ChainListPaymentToken, ChainListWithGasItem, ElementApiResponse, GetChainsWithGasResponse } from "../types";
export interface ElementChainMetadata {
chainMId: number;
chain: string;
chainId: number;
chainName: string;
aliases: string[];
}
export const ELEMENT_CHAIN_METADATA_BY_CHAIN_MID: Record<number, ElementChainMetadata> = {
1: { chainMId: 1, chain: "eth", chainId: 1, chainName: "ethereum", aliases: ["ethereum", "mainnet", "eth"] },
101: { chainMId: 101, chain: "polygon", chainId: 137, chainName: "polygon", aliases: ["polygon", "matic"] },
201: { chainMId: 201, chain: "bsc", chainId: 56, chainName: "bsc", aliases: ["bsc", "bnb", "binance", "binance smart chain"] },
401: { chainMId: 401, chain: "avalanche", chainId: 43114, chainName: "avalanche", aliases: ["avalanche", "avax"] },
601: { chainMId: 601, chain: "arbitrum", chainId: 42161, chainName: "arbitrum", aliases: ["arbitrum", "arbitrum one"] },
701: { chainMId: 701, chain: "zksync", chainId: 324, chainName: "zksync", aliases: ["zksync", "zksync era"] },
901: { chainMId: 901, chain: "linea", chainId: 59144, chainName: "linea", aliases: ["linea"] },
1101: { chainMId: 1101, chain: "opbnb", chainId: 204, chainName: "opbnb", aliases: ["opbnb"] },
1201: { chainMId: 1201, chain: "base", chainId: 8453, chainName: "base", aliases: ["base"] },
1301: { chainMId: 1301, chain: "scroll", chainId: 534352, chainName: "scroll", aliases: ["scroll"] },
1401: { chainMId: 1401, chain: "manta_pacific", chainId: 169, chainName: "manta", aliases: ["manta", "manta pacific"] },
1501: { chainMId: 1501, chain: "optimism", chainId: 10, chainName: "optimism", aliases: ["optimism", "op"] },
1601: { chainMId: 1601, chain: "mantle", chainId: 5000, chainName: "mantle", aliases: ["mantle"] },
1701: { chainMId: 1701, chain: "zkfair", chainId: 42766, chainName: "zkfair", aliases: ["zkfair"] },
1801: { chainMId: 1801, chain: "blast", chainId: 81457, chainName: "blast", aliases: ["blast"] },
1901: { chainMId: 1901, chain: "merlin", chainId: 4200, chainName: "merlin", aliases: ["merlin", "merlin chain"] },
2001: { chainMId: 2001, chain: "mode", chainId: 34443, chainName: "mode", aliases: ["mode"] },
2101: { chainMId: 2101, chain: "cyber", chainId: 7560, chainName: "cyber", aliases: ["cyber", "cyberconnect"] },
2201: { chainMId: 2201, chain: "bob", chainId: 60808, chainName: "bob", aliases: ["bob"] },
2301: { chainMId: 2301, chain: "lightlink", chainId: 1890, chainName: "lightlink", aliases: ["lightlink"] },
2501: { chainMId: 2501, chain: "nanon", chainId: 2748, chainName: "nanon", aliases: ["nanon"] },
2601: { chainMId: 2601, chain: "bera", chainId: 80094, chainName: "berachain", aliases: ["bera", "berachain"] },
2701: { chainMId: 2701, chain: "zeta", chainId: 7000, chainName: "zetachain", aliases: ["zeta", "zetachain"] },
2801: { chainMId: 2801, chain: "nibiru", chainId: 6900, chainName: "nibiru", aliases: ["nibiru"] },
2901: { chainMId: 2901, chain: "abstract", chainId: 2741, chainName: "abstract", aliases: ["abstract"] },
3001: { chainMId: 3001, chain: "monad", chainId: 143, chainName: "monad", aliases: ["monad"] },
3101: { chainMId: 3101, chain: "bitlayer", chainId: 200901, chainName: "bitlayer", aliases: ["bitlayer"] },
3201: { chainMId: 3201, chain: "mantra", chainId: 5888, chainName: "mantra", aliases: ["mantra"] }
};
const CHAIN_MID_BY_ALIAS = new Map(
Object.values(ELEMENT_CHAIN_METADATA_BY_CHAIN_MID).flatMap((metadata) =>
metadata.aliases.map((alias) => [normalizeChainName(alias), metadata.chainMId] as const)
)
);
let cachedChainsWithGas: ChainListWithGasItem[] | null = null;
function normalizeChainName(input: string): string {
return input.toLowerCase().replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
}
export function getElementChainNameByChainMId(chainMId: number): string {
const metadata = ELEMENT_CHAIN_METADATA_BY_CHAIN_MID[chainMId];
if (!metadata) {
throw new Error(`Unsupported chainMId for Element chain resolution: chainMId`);
}
return metadata.chainName;
}
function sortSupportedChainNames(chainMIds: number[]): string[] {
return chainMIds
.map((chainMId) => ELEMENT_CHAIN_METADATA_BY_CHAIN_MID[chainMId]?.chainName)
.filter((name): name is string => Boolean(name))
.sort((a, b) => a.localeCompare(b));
}
export interface ResolveElementChainInput {
chainName?: string;
chainMId?: number;
}
export interface ResolveElementChainResult {
chainMId: number;
chainName: string;
paymentTokens: ChainListPaymentToken[];
currency: string;
}
function normalizePaymentTokenSelector(input: string): string {
return input.trim().toLowerCase();
}
export function resolvePaymentToken(input: {
paymentToken?: string;
availablePaymentTokens?: ChainListPaymentToken[];
}): ChainListPaymentToken | null {
if (!input.paymentToken) {
return null;
}
const availablePaymentTokens = input.availablePaymentTokens ?? [];
const selector = normalizePaymentTokenSelector(input.paymentToken);
return (
availablePaymentTokens.find((token) => {
return (
normalizePaymentTokenSelector(token.name) === selector ||
(token.symbol ? normalizePaymentTokenSelector(token.symbol) === selector : false) ||
normalizePaymentTokenSelector(token.TokenAddress) === selector
);
}) ?? null
);
}
function formatSupportedPaymentTokens(paymentTokens: ChainListPaymentToken[]): string {
return paymentTokens
.map((token) => {
const symbol = token.symbol ? `/token.symbol` : "";
return `token.namesymbol (token.TokenAddress)`;
})
.join(", ");
}
export function resolveMintingTypeFromPaymentToken(input: {
paymentToken?: string;
availablePaymentTokens?: ChainListPaymentToken[];
fallbackMintingType?: number;
}): number {
if (!input.paymentToken) {
return input.fallbackMintingType ?? 0;
}
const availablePaymentTokens = input.availablePaymentTokens ?? [];
const matchedToken = resolvePaymentToken({
paymentToken: input.paymentToken,
availablePaymentTokens
});
if (!matchedToken) {
throw new Error(
`Unsupported paymentToken: input.paymentToken. Supported payment tokens: formatSupportedPaymentTokens(
availablePaymentTokens
)`
);
}
return matchedToken.SerId << 4;
}
export function resolvePaymentTokenFromMintingType(input: {
mintingType?: number;
availablePaymentTokens?: ChainListPaymentToken[];
}): ChainListPaymentToken | null {
if (!Number.isFinite(input.mintingType) || (input.mintingType ?? 0) <= 0) {
return null;
}
const serId = Math.floor((input.mintingType as number) / 16);
if (serId <= 0) {
return null;
}
return (input.availablePaymentTokens ?? []).find((token) => token.SerId === serId) ?? null;
}
export async function resolveElementChain(
input: ResolveElementChainInput,
deps: {
getChainsWithGas: () => Promise<ElementApiResponse<GetChainsWithGasResponse>>;
}
): Promise<ResolveElementChainResult> {
if (!cachedChainsWithGas) {
const response = await deps.getChainsWithGas();
cachedChainsWithGas = response.data.chains;
}
const supportedChainIds = cachedChainsWithGas.map((item) => item.chainMId);
let chainMId = input.chainMId;
if (input.chainName) {
chainMId = CHAIN_MID_BY_ALIAS.get(normalizeChainName(input.chainName));
if (!chainMId) {
throw new Error(
`Unsupported chainName: input.chainName. Supported chains: sortSupportedChainNames(supportedChainIds).join(", ")`
);
}
}
if (!chainMId) {
throw new Error("chainName is required");
}
const supportedChain = cachedChainsWithGas.find((item) => item.chainMId === chainMId);
if (!supportedChain) {
throw new Error(
`Unsupported chain for Element Drop: getElementChainNameByChainMId(chainMId). Supported chains: sortSupportedChainNames(
supportedChainIds
).join(", ")`
);
}
return {
chainMId,
chainName: getElementChainNameByChainMId(chainMId),
paymentTokens: supportedChain.paymentTokens,
currency: supportedChain.currency
};
}
FILE:scripts/src/cli.ts
import { readFile } from "node:fs/promises";
import { stdin as input } from "node:process";
import { createElementApiClient } from "./api/element";
import { createElementGraphqlClient } from "./api/graphql";
import { buildElementAuthorization, deriveWalletAddress, getElementIdentityByChainMId } from "./auth/jwt";
import { normalizeCreateDropInput } from "./schema";
import { deriveEditionFromMaxSupply } from "./drop-mode";
import {
getElementChainNameByChainMId,
resolveElementChain,
resolvePaymentToken,
resolvePaymentTokenFromMintingType
} from "./network/chains";
import { getRpcUrlForChainMId } from "./network/rpc";
import { sendEncodedTransaction } from "./network/transaction";
import { createDropFlow } from "./workflow/create-drop";
import { previewDropFlow } from "./workflow/preview-drop";
import { configureDropFlow, previewConfigureDrop } from "./workflow/configure-drop";
import { buildDisplayDesignAfterUpdate } from "./workflow/design-payloads";
import { createTokenFlow } from "./workflow/create-token";
import { postCreateCollectionFlow } from "./workflow/post-create-collection";
import {
extractPreRevealAnimationUrl,
extractPreRevealImageUrl,
buildPostDropSettingsPayloadFromSettings,
buildSetProjectConfigPayload,
publishDropFlow,
resolvePublishPreRevealIPFS,
waitForPreRevealIPFS,
waitForPublishedSettings
} from "./workflow/publish-drop";
import { formatSocialLinkForDisplay, normalizeWebsiteUrl } from "./workflow/links";
import { uploadSingleAsset, uploadWithExistingAuthorization } from "./workflow/uploads";
import { verifyRefGraphqlExamples } from "./workflow/verify-ref-graphql";
import { waitForCollectionContract } from "./workflow/wait-collection-contract";
import { getRequiredWalletPrivateKey, redactKnownSecrets } from "./env";
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
type CliOperationContext = {
command?: string;
chainName?: unknown;
symbol?: unknown;
slug?: unknown;
contractAddress?: unknown;
};
let activeOperationContext: CliOperationContext = {};
function setActiveOperationContext(command: string, payload: Record<string, unknown>) {
activeOperationContext = {
command,
chainName: payload.chainName ?? null,
symbol: payload.symbol ?? null,
slug: payload.slug ?? null,
contractAddress: payload.contractAddress ?? null
};
}
async function readStdin(): Promise<string> {
const chunks: Buffer[] = [];
for await (const chunk of input) {
chunks.push(Buffer.from(chunk));
}
return Buffer.concat(chunks).toString("utf8");
}
const FORBIDDEN_SECRET_PAYLOAD_KEYS = new Set([
"privateKey",
"walletPrivateKey",
"ELEMENT_WALLET_PRIVATE_KEY",
"mnemonic",
"seedPhrase"
]);
function assertNoSecretPayloadKeys(value: unknown, path = "$") {
if (Array.isArray(value)) {
value.forEach((item, index) => assertNoSecretPayloadKeys(item, `path[index]`));
return;
}
if (typeof value !== "object" || value === null) {
return;
}
for (const [key, nestedValue] of Object.entries(value)) {
const nextPath = `path.key`;
if (FORBIDDEN_SECRET_PAYLOAD_KEYS.has(key)) {
throw new Error(
`Refusing secret input at nextPath; provide wallet private key only through ELEMENT_WALLET_PRIVATE_KEY`
);
}
assertNoSecretPayloadKeys(nestedValue, nextPath);
}
}
async function readJsonArg(path?: string) {
const payload = path ? JSON.parse(await readFile(path, "utf8")) : JSON.parse(await readStdin());
assertNoSecretPayloadKeys(payload);
return payload;
}
function getPayloadPath(args: string[]) {
return args.find((arg) => !arg.startsWith("--"));
}
function listDefinedKeys(input: Record<string, unknown>, excludedKeys: string[] = []) {
return Object.keys(input).filter((key) => input[key] !== undefined && !excludedKeys.includes(key));
}
function isElementDropCollection(sourceType: string | null | undefined): boolean {
return typeof sourceType === "string" && sourceType.includes("ELEMENT_DROP");
}
function summarizeEncodedTransaction(input: {
step: string;
description: string;
transaction: { to: string; value: string; data: string };
}) {
return {
step: input.step,
description: input.description,
to: input.transaction.to,
value: input.transaction.value,
dataPrefix: input.transaction.data.slice(0, 18),
dataLength: input.transaction.data.length
};
}
function summarizeSupportedPaymentToken(token: {
name: string;
symbol?: string;
TokenAddress: string;
SerId: number;
} | null) {
if (!token) {
return null;
}
return {
name: token.name,
symbol: token.symbol ?? null,
address: token.TokenAddress
};
}
function summarizeNativePaymentToken(currency: unknown) {
if (typeof currency !== "string" || currency.trim().length === 0) {
return null;
}
return {
name: currency,
symbol: currency,
address: ZERO_ADDRESS
};
}
function summarizeResolvedPaymentToken(input: {
mintingType?: unknown;
availablePaymentTokens?: unknown[];
currency?: unknown;
}) {
const mintingType = typeof input.mintingType === "number" ? input.mintingType : undefined;
const token = summarizeSupportedPaymentToken(
resolvePaymentTokenFromMintingType({
mintingType,
availablePaymentTokens: Array.isArray(input.availablePaymentTokens)
? (input.availablePaymentTokens as never[])
: []
}) as never
);
if (token) {
return token;
}
if (mintingType === undefined || mintingType <= 0) {
return summarizeNativePaymentToken(input.currency);
}
return null;
}
function summarizeEdition(maxSupply: unknown) {
const edition = deriveEditionFromMaxSupply(maxSupply);
if (edition === "limited") {
return { value: 0, label: "limited" };
}
if (edition === "open") {
return { value: 1, label: "open" };
}
return { value: null, label: null };
}
function summarizeTimestamp(timestamp: unknown) {
if (typeof timestamp !== "number" || !Number.isFinite(timestamp) || timestamp <= 0) {
return null;
}
return {
unix: timestamp,
iso: new Date(timestamp * 1000).toISOString()
};
}
function summarizeStage(stage: Record<string, unknown>) {
return {
stageName: stage.stageName ?? null,
price: stage.price ?? null,
duration: stage.duration ?? null,
maxSupplyAtThisStage: stage.maxSupplyAtThisStage ?? null,
maxMintedPerWallet: stage.maxMintedPerWallet ?? null,
interval: stage.interval ?? null,
stageMode: stage.stageMode ?? null,
enableCallFromContract:
typeof stage.enableCallFromContract === "boolean" ? stage.enableCallFromContract : null,
enableMintToOther:
typeof stage.enableMintToOther === "boolean" ? stage.enableMintToOther : null
};
}
function summarizeSettingsSnapshot(input: {
maxSupply?: unknown;
totalMint?: unknown;
dropBeginTime?: unknown;
dropType?: unknown;
mintingType?: unknown;
stages?: unknown;
availablePaymentTokens?: unknown[];
currency?: unknown;
}) {
const edition = summarizeEdition(input.maxSupply);
const paymentToken = summarizeResolvedPaymentToken({
mintingType: input.mintingType,
availablePaymentTokens: input.availablePaymentTokens,
currency: input.currency
});
return {
maxSupply: edition.label === "open" ? null : input.maxSupply ?? null,
totalMint: input.totalMint ?? null,
dropBeginTime: summarizeTimestamp(input.dropBeginTime),
edition,
paymentToken,
stageCount: Array.isArray(input.stages) ? input.stages.length : 0,
stages: Array.isArray(input.stages)
? input.stages.map((stage) => summarizeStage(stage as Record<string, unknown>))
: []
};
}
function summarizeDesignSnapshot(input: {
bannerURL?: unknown;
previewMediaExt?: unknown;
description?: unknown;
website?: unknown;
twitter?: unknown;
instagram?: unknown;
discord?: unknown;
telegram?: unknown;
medium?: unknown;
dropFeaturedImage?: unknown;
}) {
const previewMediaExt = Array.isArray(input.previewMediaExt) ? input.previewMediaExt : [];
return {
bannerURL: input.bannerURL ?? null,
previewMediaCount: previewMediaExt.length,
previewMediaExt: previewMediaExt.map((item) => ({
image_url:
typeof item === "object" && item !== null && "image_url" in item ? (item.image_url ?? null) : null,
animation_url:
typeof item === "object" && item !== null && "animation_url" in item ? (item.animation_url ?? null) : null
})),
description: input.description ?? null,
website: normalizeWebsiteUrl(typeof input.website === "string" ? input.website : undefined) || null,
twitter:
formatSocialLinkForDisplay("twitter", typeof input.twitter === "string" ? input.twitter : undefined) || null,
instagram:
formatSocialLinkForDisplay("instagram", typeof input.instagram === "string" ? input.instagram : undefined) ||
null,
discord:
formatSocialLinkForDisplay("discord", typeof input.discord === "string" ? input.discord : undefined) || null,
telegram:
formatSocialLinkForDisplay("telegram", typeof input.telegram === "string" ? input.telegram : undefined) ||
null,
medium:
formatSocialLinkForDisplay("medium", typeof input.medium === "string" ? input.medium : undefined) || null,
dropFeaturedImage: input.dropFeaturedImage ?? null
};
}
function shouldRepublishUpdatedDrop(input: {
published?: unknown;
isPaused?: unknown;
willUpdateSettings?: unknown;
willUpdatePreReveal?: unknown;
}) {
return (
input.published === 1 &&
input.isPaused === false &&
Boolean(input.willUpdateSettings || input.willUpdatePreReveal)
);
}
function summarizePublishState(input: { published?: unknown; isPaused?: unknown }) {
if (input.published !== 1) {
return {
status: "draft",
label: "draft"
};
}
if (input.isPaused === true) {
return {
status: "paused",
label: "paused"
};
}
return {
status: "live",
label: "live"
};
}
function summarizePublishTargetState(isPaused: unknown) {
return isPaused === true
? {
status: "paused",
label: "publish but keep paused"
}
: {
status: "live",
label: "publish live"
};
}
function buildSigningSafetyNote() {
return {
privateKeyHandling:
"The private key is used only for local signing in this script and is never sent over the network.",
reminder:
"Network requests may carry derived wallet address, auth token, or signed transactions, but not the raw private key."
};
}
function buildCreateDropDryRunPreview(
payload: Record<string, unknown>,
input: {
onchainPreview?: {
createToken?: { to: string; value: string; data: string };
walletAddress?: string;
};
} = {}
) {
const normalized = normalizeCreateDropInput(payload as never);
const paymentTokens = Array.isArray(payload.paymentTokens)
? payload.paymentTokens.map((token) =>
typeof token === "object" && token !== null
? {
name: "name" in token ? token.name : undefined,
address: "TokenAddress" in token ? token.TokenAddress : undefined
}
: token
)
: [];
const selectedPaymentTokenRaw =
typeof payload.paymentToken === "string"
? (resolvePaymentToken({
paymentToken: payload.paymentToken,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? (payload.paymentTokens as never[]) : []
}) as never)
: null;
const selectedPaymentToken =
summarizeSupportedPaymentToken(selectedPaymentTokenRaw) ?? summarizeNativePaymentToken(payload.currency);
return {
command: "create-drop",
previewOnly: true,
required: {
chainName: payload.chainName ?? null,
name: payload.name ?? null,
symbol: payload.symbol ?? null,
preReveal: payload.preReveal ?? null
},
settingsPreview: summarizeSettingsSnapshot({
maxSupply: normalized.maxSupply,
dropBeginTime: normalized.dropBeginTime,
dropType: normalized.dropType,
mintingType: selectedPaymentTokenRaw ? (selectedPaymentTokenRaw as { SerId: number }).SerId << 4 : null,
stages: normalized.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
designPreview: {
preRevealSource: payload.preReveal ?? null,
bannerFilePath: payload.bannerFilePath ?? null,
previewMediaSources:
Array.isArray(payload.previewMedia) && payload.previewMedia.length > 0
? payload.previewMedia
: Array.isArray(payload.previewFilePaths) && payload.previewFilePaths.length > 0
? payload.previewFilePaths
: [payload.preReveal ?? null].filter(Boolean),
description: normalized.description || null,
website: payload.website ?? null,
twitter: payload.twitter ?? null,
instagram: payload.instagram ?? null,
discord: payload.discord ?? null,
telegram: payload.telegram ?? null,
medium: payload.medium ?? null,
dropFeaturedImage: payload.dropFeaturedImage ?? null,
note: "Create flow uploads and sets prereveal, settings, and initial design before stopping."
},
resolvedChain: {
chainName: payload.chainName ?? null,
currency: payload.currency ?? null,
supportedPaymentTokens: paymentTokens
},
selectedPaymentToken,
onchainRisk: {
hasBlockchainTransaction: true,
executionRequiresExplicitConfirmation: true,
note: "This flow deploys a new contract onchain."
},
signingSafety: buildSigningSafetyNote(),
chainOperationNotice: {
walletAddress: input.onchainPreview?.walletAddress ?? null,
requiresSignature: true,
note: "The deployment transaction is prepared for preview only and is not broadcast."
},
transactionPreview: input.onchainPreview?.createToken
? [
summarizeEncodedTransaction({
step: "createToken",
description: "Deploy the drop contract",
transaction: input.onchainPreview.createToken
})
]
: [],
willUploadImages: true,
willSendTransactions: true,
willModifyAvailability: false
};
}
function buildUpdateDropDryRunPreview(payload: Record<string, unknown>) {
const patchKeys = listDefinedKeys(payload, [
"authorization",
"walletAddress",
"chainMId",
"contractAddress",
"slug",
"getSettingsPollIntervalMs",
"getSettingsTimeoutMs"
]);
const hasPreRevealPatch = Boolean(payload.preReveal);
const hasPreviewMediaPatch = Array.isArray(payload.previewMedia) && payload.previewMedia.length > 0;
const hasPreviewFilePathsPatch = Array.isArray(payload.previewFilePaths) && payload.previewFilePaths.length > 0;
const hasDesignPatch = Boolean(
hasPreviewMediaPatch ||
payload.bannerFilePath ||
hasPreviewFilePathsPatch ||
(payload.name ??
payload.description ??
payload.dropFeaturedImage)
);
const hasCollectionMetadataPatch = Boolean(
payload.website ??
payload.twitter ??
payload.instagram ??
payload.discord ??
payload.telegram ??
payload.medium
);
return {
command: "update-drop",
previewOnly: true,
target: {
chainName: payload.chainName ?? null,
slug: payload.slug ?? null
},
resolvedTarget: {
contractAddress: payload.contractAddress ?? null
},
resolvedChain: {
chainName: payload.chainName ?? null,
currency: payload.currency ?? null,
supportedPaymentTokens: Array.isArray(payload.paymentTokens)
? payload.paymentTokens.map((token) =>
typeof token === "object" && token !== null
? {
name: "name" in token ? token.name : undefined,
address: "TokenAddress" in token ? token.TokenAddress : undefined
}
: token
)
: []
},
patchKeys,
patchPreview: {
settings: {
preReveal: payload.preReveal ?? null,
dropType: payload.dropType ?? null,
maxSupply: payload.maxSupply ?? null,
dropBeginTime: summarizeTimestamp(payload.dropBeginTime),
paymentToken: payload.paymentToken ?? null,
stages:
Array.isArray(payload.stages) && payload.stages.length > 0
? payload.stages.map((stage) => summarizeStage(stage as Record<string, unknown>))
: []
},
design: {
previewMedia:
Array.isArray(payload.previewMedia) && payload.previewMedia.length > 0 ? payload.previewMedia : [],
bannerFilePath: payload.bannerFilePath ?? null,
previewFilePaths:
Array.isArray(payload.previewFilePaths) && payload.previewFilePaths.length > 0 ? payload.previewFilePaths : [],
name: payload.name ?? null,
description: payload.description ?? null,
website: payload.website ?? null,
twitter: payload.twitter ?? null,
instagram: payload.instagram ?? null,
discord: payload.discord ?? null,
telegram: payload.telegram ?? null,
medium: payload.medium ?? null,
dropFeaturedImage: payload.dropFeaturedImage ?? null
}
},
willReadCurrentSettings: true,
willReadCurrentDesign: hasDesignPatch,
willUpdatePreReveal: hasPreRevealPatch,
onchainRisk: {
hasBlockchainTransaction: false,
executionRequiresExplicitConfirmation: false,
note: "This flow updates remote settings, prereveal, design, or collection profile fields and does not send an onchain transaction by itself."
},
signingSafety: buildSigningSafetyNote(),
transactionPreview: [],
willUploadImages: Boolean(
payload.preReveal || hasPreviewMediaPatch || payload.bannerFilePath || hasPreviewFilePathsPatch
),
willUpdateSettings: true,
willUpdateDesign: hasDesignPatch,
willUpdateCollectionProfile: hasCollectionMetadataPatch,
willSendTransactions: false,
willModifyAvailability: false
};
}
function buildPublishDropDryRunPreview(
payload: Record<string, unknown>,
input: {
onchainPreview?: {
setProjectConfig?: { to: string; value: string; data: string };
walletAddress?: string;
setProjectConfigPayload?: { isPaused?: boolean };
settings?: {
maxSupply?: number;
totalMint?: number;
dropBeginTime?: number;
dropType?: number;
mintingType?: number;
stages?: unknown[];
isPaused?: boolean;
};
tempURL?: {
preReveal?: {
imageURL?: string;
animationURL?: string;
};
};
};
} = {}
) {
return {
command: "publish-drop",
previewOnly: true,
target: {
chainName: payload.chainName ?? null,
slug: payload.slug ?? null
},
resolvedTarget: {
contractAddress: payload.contractAddress ?? null
},
resolvedChain: {
chainName: payload.chainName ?? null,
currency: payload.currency ?? null,
supportedPaymentTokens: Array.isArray(payload.paymentTokens)
? payload.paymentTokens.map((token) =>
typeof token === "object" && token !== null
? {
name: "name" in token ? token.name : undefined,
address: "TokenAddress" in token ? token.TokenAddress : undefined
}
: token
)
: []
},
selectedPaymentToken: summarizeSupportedPaymentToken(
resolvePaymentTokenFromMintingType({
mintingType: input.onchainPreview?.settings?.mintingType,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? (payload.paymentTokens as never[]) : []
}) as never
) ?? summarizeNativePaymentToken(payload.currency),
onchainRisk: {
hasBlockchainTransaction: true,
executionRequiresExplicitConfirmation: true,
note: "This flow sends the publish transaction onchain and can make the drop live."
},
signingSafety: buildSigningSafetyNote(),
chainOperationNotice: {
walletAddress: input.onchainPreview?.walletAddress ?? null,
requiresSignature: true,
note:
input.onchainPreview?.setProjectConfigPayload?.isPaused === true
? "The publish transaction is prepared for preview only, will keep the drop paused, and is not broadcast."
: "The publish transaction is prepared for preview only and is not broadcast."
},
publishTarget: {
state: summarizePublishTargetState(
input.onchainPreview?.setProjectConfigPayload?.isPaused ?? payload.isPaused
)
},
preRevealCheck: {
imageURL: input.onchainPreview?.tempURL ? extractPreRevealImageUrl(input.onchainPreview.tempURL as never) : null,
animationURL:
input.onchainPreview?.tempURL ? extractPreRevealAnimationUrl(input.onchainPreview.tempURL as never) : null
},
publishSequence: [
"Read current prereveal media status and confirm prereveal OSS image exists",
"Trigger/check prereveal OSS to IPFS resolution",
"Poll preRevealIPFS until it becomes non-empty",
"Prepare postSettings payload from current settings",
"Encode setProjectConfig with resolved preRevealIPFS",
"Broadcast publish transaction only during confirmed execution",
"Alternate callback/updateProjectConfig and edit/settings polling until publish state is synchronized"
],
settingsPreview: input.onchainPreview?.settings
? summarizeSettingsSnapshot({
maxSupply: input.onchainPreview.settings.maxSupply,
totalMint: input.onchainPreview.settings.totalMint,
dropBeginTime: input.onchainPreview.settings.dropBeginTime,
dropType: input.onchainPreview.settings.dropType,
mintingType: input.onchainPreview.settings.mintingType,
stages: input.onchainPreview.settings.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
})
: null,
publishModeNote:
input.onchainPreview?.setProjectConfigPayload?.isPaused === true
? "This publish will leave the drop paused."
: "This publish will make the drop live.",
transactionPreview: input.onchainPreview?.setProjectConfig
? [
summarizeEncodedTransaction({
step: "setProjectConfig",
description: "Publish the drop onchain",
transaction: input.onchainPreview.setProjectConfig
})
]
: [],
willUploadImages: false,
willSendTransactions: true,
willModifyAvailability: true
};
}
function printHelp() {
console.log(`element-drop scripts
Lifecycle commands:
create-drop Create a new drop, upload prereveal and initial design, and stop before publish.
preview-drop Read-only preview of the current settings, design, and prereveal media.
update-drop Update only the fields the user explicitly provides.
publish-drop Publish an already configured drop.
list-chains Read-only list of Element-supported chains and payment tokens.
list-user-collections Read-only list of a user's collections on a supported chain.
list-user-drops Read-only list of a user's Element Drops on a supported chain.
get-contract-by-slug Read-only resolve of collection contract address by slug.
Global flags:
--preview Preview a state-changing lifecycle command without mutating anything.
Advanced utilities (not the default user-facing path):
create-token
post-create-collection
get-settings
post-settings
get-design
post-design
upload-prereveal
upload-design
wait-collection-contract
wait-prereveal-ipfs
verify-ref-graphql
Minimal lifecycle payloads:
create-drop
{
"chainName": "base",
"name": "My Drop",
"symbol": "F",
"preReveal": "/absolute/path/to/image.png"
}
preview-drop
{
"chainName": "base",
"slug": "ffffff-510bce"
}
update-drop
{
"chainName": "base",
"slug": "my-drop-510bce",
"paymentToken": "ETH",
"maxSupply": 999,
"previewMedia": [
"/absolute/path/to/preview-1.png"
]
}
publish-drop
{
"chainName": "base",
"slug": "my-drop-510bce"
}
list-user-drops
{
"chainName": "base"
}
`);
}
async function main() {
const args = process.argv.slice(2);
const command = args[0];
const commandArgs = args.slice(1);
const dryRun = commandArgs.includes("--dry-run") || commandArgs.includes("--preview");
const filePath = getPayloadPath(commandArgs);
const api = createElementApiClient();
const graphql = createElementGraphqlClient();
if (!command || command === "help" || command === "--help" || command === "-h") {
printHelp();
return;
}
async function resolvePayloadChain<T extends Record<string, unknown>>(payload: T): Promise<T & {
chainMId: number;
chainName: string;
paymentTokens: unknown[];
currency: string;
}> {
activeOperationContext = {
command,
chainName: payload.chainName ?? payload.chainMId ?? null,
symbol: payload.symbol ?? null,
slug: payload.slug ?? null,
contractAddress: payload.contractAddress ?? null
};
const resolved = await resolveElementChain(
{
chainName: typeof payload.chainName === "string" ? payload.chainName : undefined,
chainMId: typeof payload.chainMId === "number" ? payload.chainMId : undefined
},
{
getChainsWithGas: api.getChainsWithGas
}
);
return {
...payload,
chainMId: resolved.chainMId,
chainName: resolved.chainName,
paymentTokens: resolved.paymentTokens,
currency: resolved.currency
};
}
async function createAuthorization(chainMId: number) {
const privateKey = getRequiredWalletPrivateKey();
const walletAddress = (await deriveWalletAddress({ privateKey })).toLowerCase();
const auth = await buildElementAuthorization(
{
getLoginNonce: graphql.getLoginNonce,
loginAuth: graphql.loginAuth
},
{
privateKey,
walletAddress,
chainMId
}
);
return {
authorization: auth.authorization,
walletAddress,
nonce: auth.nonce,
loginMessage: auth.message,
identity: auth.identity
};
}
async function getWalletAddressFromEnv() {
const privateKey = getRequiredWalletPrivateKey();
return (await deriveWalletAddress({ privateKey })).toLowerCase();
}
async function buildCreateDropOnchainPreview(payload: {
chainMId: number;
name: string;
symbol: string;
}) {
const auth = await createAuthorization(payload.chainMId);
const encoded = await api.postCreateToken(
auth.authorization,
{
chainMId: payload.chainMId,
name: payload.name,
symbol: payload.symbol
},
auth.walletAddress
);
return {
walletAddress: auth.walletAddress,
createToken: encoded.data
};
}
async function buildPublishDropOnchainPreview(payload: {
authorization: string;
walletAddress: string;
chainMId: number;
contractAddress: string;
dropID: number;
isPaused?: boolean;
preRevealIPFSPollIntervalMs?: number;
preRevealIPFSTimeoutMs?: number;
}) {
const settingsResponse = await api.getDropSettings(
{
chainMId: payload.chainMId,
contractAddress: payload.contractAddress
},
payload.walletAddress
);
const preRevealResolution = await resolvePublishPreRevealIPFS(
{
authorization: payload.authorization,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: payload.dropID,
walletAddress: payload.walletAddress,
pollIntervalMs: payload.preRevealIPFSPollIntervalMs,
timeoutMs: payload.preRevealIPFSTimeoutMs
},
{
getTempURL: api.getTempURL,
getPreRevealIPFS: api.getPreRevealIPFS
}
);
const postSettingsPayload = buildPostDropSettingsPayloadFromSettings({
settings: settingsResponse.data,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress
});
const setProjectConfigPayload = buildSetProjectConfigPayload({
settings: settingsResponse.data,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
preRevealIPFS: preRevealResolution.preRevealIPFS.preRevealIPFS,
isPaused: payload.isPaused
});
const encoded = await api.postSetProjectConfig(
payload.authorization,
setProjectConfigPayload,
payload.walletAddress
);
return {
walletAddress: payload.walletAddress,
settings: settingsResponse.data,
tempURL: preRevealResolution.tempURL,
preRevealIPFS: preRevealResolution.preRevealIPFS,
postSettingsPayload,
setProjectConfigPayload,
setProjectConfig: encoded.data
};
}
async function resolveContractAddressBySlug(input: {
chainMId: number;
slug?: string;
contractAddress?: string;
}) {
if (!input.slug) {
if (!input.contractAddress) {
throw new Error("slug is required");
}
return {
slug: undefined,
contractAddress: input.contractAddress
};
}
const collection = await graphql.getCollectionDetailFromEditors(input.slug);
const expectedBlockChain = getElementIdentityByChainMId(input.chainMId, ZERO_ADDRESS).blockChain;
const contract =
collection.contracts.find(
(item) =>
item.blockChain.chain === expectedBlockChain.chain && item.blockChain.chainId === expectedBlockChain.chainId
) ?? null;
if (!contract) {
throw new Error(`No contract found for slug input.slug on chain getElementChainNameByChainMId(input.chainMId)`);
}
if (
input.contractAddress &&
input.contractAddress.toLowerCase() !== contract.address.toLowerCase()
) {
throw new Error(
`slug input.slug resolved to contractAddress contract.address, but payload provided input.contractAddress`
);
}
return {
slug: collection.slug,
contractAddress: contract.address
};
}
async function resolveDropLocator<T extends Record<string, unknown>>(
payload: T,
input: {
needDropID?: boolean;
walletAddress?: string;
} = {}
): Promise<T & { slug?: string; contractAddress: string; dropID?: number }> {
const resolvedContract = await resolveContractAddressBySlug({
chainMId: payload.chainMId as number,
slug: typeof payload.slug === "string" ? payload.slug : undefined,
contractAddress: typeof payload.contractAddress === "string" ? payload.contractAddress : undefined
});
let dropID =
typeof payload.dropID === "number" && Number.isFinite(payload.dropID) ? payload.dropID : undefined;
if (input.needDropID && dropID === undefined) {
const walletAddress = input.walletAddress ?? (await getWalletAddressFromEnv());
const settings = await api.getDropSettings(
{
chainMId: payload.chainMId as number,
contractAddress: resolvedContract.contractAddress
},
walletAddress
);
dropID = settings.data.dropID;
if (!(dropID > 0)) {
throw new Error(`dropID is not available yet for slug resolvedContract.slug ?? payload.slug ?? ""`.trim());
}
}
return {
...payload,
slug: resolvedContract.slug ?? (typeof payload.slug === "string" ? payload.slug : undefined),
contractAddress: resolvedContract.contractAddress,
...(dropID !== undefined ? { dropID } : {})
};
}
if (command === "preview") {
const payload = await readJsonArg(filePath);
console.log(JSON.stringify(payload, null, 2));
return;
}
if (command === "list-chains") {
const response = await api.getChainsWithGas();
const chains = response.data.chains.map((chain) => ({
chainName: (() => {
try {
return getElementChainNameByChainMId(chain.chainMId);
} catch {
return "unknown";
}
})(),
currency: chain.currency,
paymentTokens: chain.paymentTokens.map((token) => ({
name: token.name,
address: token.TokenAddress
}))
}));
console.log(JSON.stringify({ chains }, null, 2));
return;
}
if (command === "list-user-collections") {
const payload = await resolvePayloadChain(await readJsonArg(filePath));
const walletAddress = typeof payload.walletAddress === "string" && payload.walletAddress.length > 0
? payload.walletAddress.toLowerCase()
: await getWalletAddressFromEnv();
const identity = getElementIdentityByChainMId(payload.chainMId, walletAddress);
const result = await graphql.getUserCollectionList({
identity,
first: typeof payload.first === "number" ? payload.first : undefined,
after: typeof payload.after === "string" ? payload.after : undefined,
before: typeof payload.before === "string" ? payload.before : undefined,
last: typeof payload.last === "number" ? payload.last : undefined
});
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
walletAddress,
totalCollections: result.items.length
},
walletAddress,
chainName: payload.chainName,
collections: result.items.map((item) => ({
slug: item.slug,
name: item.name,
isVerified: item.isVerified,
imageUrl: item.imageUrl,
assetCount: item.stats.assetCount
})),
pageInfo: result.pageInfo
},
null,
2
)
);
return;
}
if (command === "list-user-drops") {
const payload = await resolvePayloadChain(await readJsonArg(filePath));
const walletAddress =
typeof payload.walletAddress === "string" && payload.walletAddress.length > 0
? payload.walletAddress.toLowerCase()
: await getWalletAddressFromEnv();
const identity = getElementIdentityByChainMId(payload.chainMId, walletAddress);
const result = await graphql.getUserCollectionList({
identity,
first: typeof payload.first === "number" ? payload.first : undefined,
after: typeof payload.after === "string" ? payload.after : undefined,
before: typeof payload.before === "string" ? payload.before : undefined,
last: typeof payload.last === "number" ? payload.last : undefined
});
const drops = result.items
.filter((item) => item.contracts.some((contract) => isElementDropCollection(contract.sourceType)))
.map((item) => ({
name: item.name,
slug: item.slug,
isVerified: item.isVerified,
imageUrl: item.imageUrl,
assetCount: item.stats.assetCount
}));
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
walletAddress,
totalDrops: drops.length
},
walletAddress,
chainName: payload.chainName,
drops,
pageInfo: result.pageInfo
},
null,
2
)
);
return;
}
if (command === "get-contract-by-slug") {
const payload = await readJsonArg(filePath);
const collection = await graphql.getCollectionDetailFromEditors(payload.slug);
const contract = collection.contracts[0] ?? null;
console.log(
JSON.stringify(
{
summary: {
slug: collection.slug,
name: collection.name,
contractAddress: contract?.address ?? null
},
slug: collection.slug,
name: collection.name,
contractAddress: contract?.address ?? null,
blockChain: contract?.blockChain ?? null,
sourceType: contract?.sourceType ?? null
},
null,
2
)
);
return;
}
if (command === "create-token") {
const payload = await resolvePayloadChain(await readJsonArg(filePath));
setActiveOperationContext(command, payload);
const result = await createTokenFlow(payload, {
deriveAddress: deriveWalletAddress,
resolveRpcUrl: getRpcUrlForChainMId,
createAuthorization: (input) =>
buildElementAuthorization(
{
getLoginNonce: graphql.getLoginNonce,
loginAuth: graphql.loginAuth
},
input
),
postCreateToken: api.postCreateToken,
sendTransaction: sendEncodedTransaction
});
const output: Record<string, unknown> = { ...result };
output.summary = {
chainName: payload.chainName,
symbol: payload.symbol,
contractAddress: result.transaction.contractAddress ?? payload.contractAddress ?? null,
transactionHash: result.transaction.hash
};
const contractAddress = result.transaction.contractAddress ?? payload.contractAddress;
if (contractAddress) {
output.postCreateCollection = await postCreateCollectionFlow(
{
chainMId: payload.chainMId,
contractAddress,
authorization: result.preflight.authorization,
imageFilePath: payload.preReveal,
pollIntervalMs: payload.pollIntervalMs,
timeoutMs: payload.timeoutMs
},
{
getCollectionContract: graphql.getCollectionContract,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors,
collectionEdit: graphql.collectionEdit
}
);
}
console.log(JSON.stringify(output, null, 2));
return;
}
if (command === "create-drop") {
const payload = await resolvePayloadChain(await readJsonArg(filePath));
setActiveOperationContext(command, payload);
if (dryRun) {
const onchainPreview = await buildCreateDropOnchainPreview({
chainMId: payload.chainMId,
name: String(payload.name),
symbol: String(payload.symbol)
});
console.log(JSON.stringify(buildCreateDropDryRunPreview(payload, { onchainPreview }), null, 2));
return;
}
const result = await createDropFlow(payload, {
createTokenFlow,
postCreateCollectionFlow,
uploadWithExistingAuthorization,
getDropSettings: api.getDropSettings,
postDropSettings: api.postDropSettings,
getOssSignSingle: api.getOssSignSingle,
postPreReveal: api.postPreReveal,
postDesign: api.postDesign,
uploadAsset: uploadSingleAsset,
createAuthorization,
deriveAddress: deriveWalletAddress,
resolveRpcUrl: getRpcUrlForChainMId,
createAuthorizationForToken: (input) =>
buildElementAuthorization(
{
getLoginNonce: graphql.getLoginNonce,
loginAuth: graphql.loginAuth
},
input
),
postCreateToken: api.postCreateToken,
sendTransaction: sendEncodedTransaction,
getCollectionContract: graphql.getCollectionContract,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors,
collectionEdit: graphql.collectionEdit
});
console.log(
JSON.stringify(
{
summary: result.summary,
settings: summarizeSettingsSnapshot({
maxSupply: result.initialSettingsPayload.maxSupply,
dropBeginTime: result.initialSettingsPayload.dropBeginTime,
dropType: result.initialSettingsPayload.dropType,
mintingType: result.initialSettingsPayload.mintingType,
stages: result.initialSettingsPayload.stagesUpdate,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
design: summarizeDesignSnapshot(result.designUpload.payload),
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "configure-drop") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)));
setActiveOperationContext(command, payload);
if (dryRun) {
const auth =
payload.authorization && payload.walletAddress
? {
authorization: payload.authorization,
walletAddress: payload.walletAddress
}
: await createAuthorization(payload.chainMId);
const preview = await previewConfigureDrop(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
slug: payload.slug,
patch: payload
},
{
getDropSettings: api.getDropSettings,
getDropDesign: api.getDropDesign,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors
}
);
console.log(JSON.stringify(preview, null, 2));
return;
}
const auth =
payload.authorization && payload.walletAddress
? {
authorization: payload.authorization,
walletAddress: payload.walletAddress
}
: await createAuthorization(payload.chainMId);
const result = await configureDropFlow(
{
...payload,
authorization: auth.authorization,
walletAddress: auth.walletAddress
},
{
uploadWithExistingAuthorization,
getDropSettings: api.getDropSettings,
getDropDesign: api.getDropDesign,
postDropSettings: api.postDropSettings,
getOssSignSingle: api.getOssSignSingle,
postPreReveal: api.postPreReveal,
postDesign: api.postDesign,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors,
collectionEdit: graphql.collectionEdit,
uploadAsset: uploadSingleAsset
}
);
const displayDesignAfterConfigure = buildDisplayDesignAfterUpdate({
current: result.currentDesignResponse?.data ?? null,
designPayload: result.designPayload,
collectionEditPayload: result.collectionEditPayload
});
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: result.contractAddress,
slug: result.slug,
dropUrl: result.urls?.dropUrl ?? null,
collectionUrl: result.urls?.collectionUrl ?? null,
editUrl: result.urls?.editUrl ?? null,
preRevealUrl: result.preRevealUpload?.publicUrls[0] ?? null,
bannerUrl: result.designBannerUrl ?? null
},
settingsAfterUpdate: summarizeSettingsSnapshot({
maxSupply: result.settingsAfterConfigure.data.maxSupply,
totalMint: result.settingsAfterConfigure.data.totalMint,
dropBeginTime: result.settingsAfterConfigure.data.dropBeginTime,
dropType: result.settingsAfterConfigure.data.dropType,
mintingType: result.settingsAfterConfigure.data.mintingType,
stages: result.settingsAfterConfigure.data.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : []
}),
...(displayDesignAfterConfigure
? { designAfterUpdate: summarizeDesignSnapshot(displayDesignAfterConfigure) }
: {}),
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "update-drop") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)));
setActiveOperationContext(command, payload);
if (dryRun) {
const auth =
payload.authorization && payload.walletAddress
? {
authorization: payload.authorization,
walletAddress: payload.walletAddress
}
: await createAuthorization(payload.chainMId);
const preview = await previewConfigureDrop(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
slug: payload.slug,
patch: payload
},
{
getDropSettings: api.getDropSettings,
getDropDesign: api.getDropDesign,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors
}
);
const currentPaymentToken = summarizeResolvedPaymentToken({
mintingType: preview.currentSettings.data?.mintingType,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
});
const nextPaymentToken = summarizeResolvedPaymentToken({
mintingType: preview.settingsPayload?.mintingType ?? preview.currentSettings.data?.mintingType,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
});
const requiresRepublish = shouldRepublishUpdatedDrop({
published: preview.currentSettings.data?.published,
isPaused: preview.currentSettings.data?.isPaused,
willUpdateSettings: preview.summary.willUpdateSettings,
willUpdatePreReveal: preview.summary.willUpdatePreReveal
});
const republishPreview =
requiresRepublish
? buildPublishDropDryRunPreview(payload, {
onchainPreview: await buildPublishDropOnchainPreview({
authorization: auth.authorization,
walletAddress: auth.walletAddress,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: preview.summary.dropID,
preRevealIPFSPollIntervalMs: payload.preRevealIPFSPollIntervalMs,
preRevealIPFSTimeoutMs: payload.preRevealIPFSTimeoutMs
})
})
: null;
console.log(
JSON.stringify(
requiresRepublish
? {
command: "update-drop",
previewOnly: true,
target: {
chainName: payload.chainName ?? null,
slug: payload.slug ?? null,
contractAddress: payload.contractAddress ?? null
},
current: {
publishState: summarizePublishState({
published: preview.currentSettings.data?.published,
isPaused: preview.currentSettings.data?.isPaused
}),
batch: preview.currentSettings.data?.batch ?? null,
settings: summarizeSettingsSnapshot({
maxSupply: preview.currentSettings.data?.maxSupply,
totalMint: preview.currentSettings.data?.totalMint,
dropBeginTime: preview.currentSettings.data?.dropBeginTime,
dropType: preview.currentSettings.data?.dropType,
mintingType: preview.currentSettings.data?.mintingType,
stages: preview.currentSettings.data?.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
...(preview.currentDesign?.data
? { design: summarizeDesignSnapshot(preview.currentDesign.data) }
: {})
},
currentPaymentToken,
nextPaymentToken,
...(preview.settingsPayload
? { settingsPreview: summarizeSettingsSnapshot({
maxSupply: preview.settingsPayload.maxSupply,
dropBeginTime: preview.settingsPayload.dropBeginTime,
dropType: preview.settingsPayload.dropType,
mintingType: preview.settingsPayload.mintingType,
stages: preview.settingsPayload.stagesUpdate,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}) }
: {}),
...(preview.designPayload ? { designPreview: summarizeDesignSnapshot(preview.designPayload) } : {}),
onchainRisk: {
hasBlockchainTransaction: true,
executionRequiresExplicitConfirmation: true,
note:
"This drop is already live, and the requested settings or prereveal update requires republish with an onchain transaction."
},
signingSafety: buildSigningSafetyNote(),
republishReason:
"The current drop is live and this patch changes settings or prereveal, so update-drop will continue into publish flow.",
...(republishPreview ? { republishPreview } : {})
}
: {
command: "update-drop",
previewOnly: true,
target: {
chainName: payload.chainName ?? null,
slug: payload.slug ?? null,
contractAddress: payload.contractAddress ?? null
},
current: {
publishState: summarizePublishState({
published: preview.currentSettings.data?.published,
isPaused: preview.currentSettings.data?.isPaused
}),
batch: preview.currentSettings.data?.batch ?? null,
settings: summarizeSettingsSnapshot({
maxSupply: preview.currentSettings.data?.maxSupply,
totalMint: preview.currentSettings.data?.totalMint,
dropBeginTime: preview.currentSettings.data?.dropBeginTime,
dropType: preview.currentSettings.data?.dropType,
mintingType: preview.currentSettings.data?.mintingType,
stages: preview.currentSettings.data?.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
...(preview.currentDesign?.data
? { design: summarizeDesignSnapshot(preview.currentDesign.data) }
: {})
},
currentPaymentToken,
nextPaymentToken,
...(preview.settingsPayload
? { settingsPreview: summarizeSettingsSnapshot({
maxSupply: preview.settingsPayload.maxSupply,
dropBeginTime: preview.settingsPayload.dropBeginTime,
dropType: preview.settingsPayload.dropType,
mintingType: preview.settingsPayload.mintingType,
stages: preview.settingsPayload.stagesUpdate,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}) }
: {}),
...(preview.designPayload ? { designPreview: summarizeDesignSnapshot(preview.designPayload) } : {}),
onchainRisk: {
hasBlockchainTransaction: false,
executionRequiresExplicitConfirmation: false,
note:
(preview.currentSettings.data?.published ?? 0) === 1
? preview.currentSettings.data?.isPaused === true
? "This drop is already paused, so update-drop applies the requested offchain changes without forcing republish."
: "This flow only changes design or collection profile fields, so it does not require republish or an onchain transaction."
: "This flow updates remote settings, prereveal, design, or collection profile fields and does not send an onchain transaction by itself."
},
signingSafety: buildSigningSafetyNote(),
transactionPreview: []
},
null,
2
)
);
return;
}
const auth =
payload.authorization && payload.walletAddress
? {
authorization: payload.authorization,
walletAddress: payload.walletAddress
}
: await createAuthorization(payload.chainMId);
const result = await configureDropFlow(
{
...payload,
authorization: auth.authorization,
walletAddress: auth.walletAddress
},
{
uploadWithExistingAuthorization,
getDropSettings: api.getDropSettings,
getDropDesign: api.getDropDesign,
postDropSettings: api.postDropSettings,
getOssSignSingle: api.getOssSignSingle,
postPreReveal: api.postPreReveal,
postDesign: api.postDesign,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors,
collectionEdit: graphql.collectionEdit,
uploadAsset: uploadSingleAsset
}
);
const republishResult =
shouldRepublishUpdatedDrop({
published: result.currentSettings.published,
isPaused: result.currentSettings.isPaused,
willUpdateSettings: Boolean(result.settingsPayload),
willUpdatePreReveal: Boolean(result.preRevealUpload)
})
? await publishDropFlow(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress,
rpcUrl: await getRpcUrlForChainMId(payload.chainMId),
chainMId: payload.chainMId,
contractAddress: result.contractAddress,
dropID: result.dropID,
getSettingsPollIntervalMs: payload.getSettingsPollIntervalMs,
getSettingsTimeoutMs: payload.getSettingsTimeoutMs,
preRevealIPFSPollIntervalMs: payload.preRevealIPFSPollIntervalMs,
preRevealIPFSTimeoutMs: payload.preRevealIPFSTimeoutMs
},
{
getDropSettings: api.getDropSettings,
getPreRevealIPFS: api.getPreRevealIPFS,
getTempURL: api.getTempURL,
postDropSettings: api.postDropSettings,
postSetProjectConfig: api.postSetProjectConfig,
sendTransaction: sendEncodedTransaction,
postCallbackUpdateProjectConfig: api.postCallbackUpdateProjectConfig
}
)
: null;
const displayDesignAfterUpdate = buildDisplayDesignAfterUpdate({
current: result.currentDesignResponse?.data ?? null,
designPayload: result.designPayload,
collectionEditPayload: result.collectionEditPayload
});
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: result.contractAddress,
slug: result.slug,
dropUrl: result.urls?.dropUrl ?? null,
collectionUrl: result.urls?.collectionUrl ?? null,
editUrl: result.urls?.editUrl ?? null,
preRevealUrl: result.preRevealUpload?.publicUrls[0] ?? null,
bannerUrl: result.designBannerUrl ?? null,
republished: Boolean(republishResult),
publishTransactionHash: republishResult?.setProjectConfigTransaction.hash ?? null
},
settingsAfterUpdate: summarizeSettingsSnapshot({
maxSupply: result.settingsAfterConfigure.data.maxSupply,
totalMint: result.settingsAfterConfigure.data.totalMint,
dropBeginTime: result.settingsAfterConfigure.data.dropBeginTime,
dropType: result.settingsAfterConfigure.data.dropType,
mintingType: result.settingsAfterConfigure.data.mintingType,
stages: result.settingsAfterConfigure.data.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
...(displayDesignAfterUpdate ? { designAfterUpdate: summarizeDesignSnapshot(displayDesignAfterUpdate) } : {}),
...(republishResult
? { publishResult: {
publishState: summarizePublishState({
published: republishResult.published.settings.published,
isPaused: republishResult.published.settings.isPaused
}),
publishTransactionHash: republishResult.setProjectConfigTransaction.hash,
settings: summarizeSettingsSnapshot({
maxSupply: republishResult.published.settings.maxSupply,
totalMint: republishResult.published.settings.totalMint,
dropBeginTime: republishResult.published.settings.dropBeginTime,
dropType: republishResult.published.settings.dropType,
mintingType: republishResult.published.settings.mintingType,
stages: republishResult.published.settings.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
})
} }
: {}),
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "preview-drop") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)));
setActiveOperationContext(command, payload);
const auth =
payload.authorization && payload.walletAddress
? {
authorization: payload.authorization,
walletAddress: payload.walletAddress
}
: await createAuthorization(payload.chainMId);
const result = await previewDropFlow(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
slug: payload.slug,
page: payload.page,
pageSize: payload.pageSize
},
{
getDropSettings: api.getDropSettings,
getDropDesign: api.getDropDesign,
getTempURL: api.getTempURL
}
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
...result.summary,
paymentToken: summarizeResolvedPaymentToken({
mintingType: result.settings.data.mintingType,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
})
},
settings: summarizeSettingsSnapshot({
maxSupply: result.settings.data.maxSupply,
totalMint: result.settings.data.totalMint,
dropBeginTime: result.settings.data.dropBeginTime,
dropType: result.settings.data.dropType,
mintingType: result.settings.data.mintingType,
stages: result.settings.data.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
design: result.design ? summarizeDesignSnapshot(result.design.data) : null,
preRevealMedia: result.tempURL
? {
imageURL: extractPreRevealImageUrl(result.tempURL.data),
animationURL: extractPreRevealAnimationUrl(result.tempURL.data)
}
: null
},
null,
2
)
);
return;
}
if (command === "wait-collection-contract") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)));
setActiveOperationContext(command, payload);
const result = await waitForCollectionContract(
{
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
pollIntervalMs: payload.pollIntervalMs,
timeoutMs: payload.timeoutMs
},
{
getCollectionContract: graphql.getCollectionContract
}
);
console.log(JSON.stringify(result, null, 2));
return;
}
if (command === "post-create-collection") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)));
setActiveOperationContext(command, payload);
const authorization =
payload.authorization ??
(
await createAuthorization(payload.chainMId)
).authorization;
const result = await postCreateCollectionFlow(
{
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
authorization,
imageFilePath: payload.imageFilePath ?? payload.preReveal,
pollIntervalMs: payload.pollIntervalMs,
timeoutMs: payload.timeoutMs
},
{
getCollectionContract: graphql.getCollectionContract,
getMutateToken: graphql.getMutateToken,
getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors,
collectionEdit: graphql.collectionEdit
}
);
console.log(JSON.stringify({ authorization, ...result }, null, 2));
return;
}
if (command === "wait-prereveal-ipfs") {
const walletAddress = await getWalletAddressFromEnv();
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)), {
needDropID: true,
walletAddress
});
setActiveOperationContext(command, payload);
const result = await waitForPreRevealIPFS(
{
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: payload.dropID,
walletAddress,
pollIntervalMs: payload.pollIntervalMs,
timeoutMs: payload.timeoutMs
},
{
getPreRevealIPFS: api.getPreRevealIPFS
}
);
console.log(JSON.stringify({ walletAddress, ...result }, null, 2));
return;
}
if (command === "wait-published-settings") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)), {
needDropID: true
});
setActiveOperationContext(command, payload);
const walletAddress = await getWalletAddressFromEnv();
const result = await waitForPublishedSettings(
{
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: payload.dropID,
walletAddress,
expectedPublished: typeof payload.expectedPublished === "number" ? payload.expectedPublished : undefined,
pollIntervalMs: payload.pollIntervalMs,
timeoutMs: payload.timeoutMs
},
{
postCallbackUpdateProjectConfig: api.postCallbackUpdateProjectConfig,
getDropSettings: api.getDropSettings
}
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress
},
walletAddress,
publishState: summarizePublishState({
published: result.settings.published,
isPaused: result.settings.isPaused
}),
settings: summarizeSettingsSnapshot({
maxSupply: result.settings.maxSupply,
totalMint: result.settings.totalMint,
dropBeginTime: result.settings.dropBeginTime,
dropType: result.settings.dropType,
mintingType: result.settings.mintingType,
stages: result.settings.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
callbackResponse: result.callbackResponse,
attempts: result.attempts,
elapsedMs: result.elapsedMs
},
null,
2
)
);
return;
}
if (command === "publish-drop") {
const rawPayload = await readJsonArg(filePath);
const resolvedChainPayload = await resolvePayloadChain(rawPayload);
const auth = await createAuthorization(resolvedChainPayload.chainMId);
const payload = await resolveDropLocator(resolvedChainPayload, {
needDropID: true,
walletAddress: auth.walletAddress
});
setActiveOperationContext(command, payload);
if (dryRun) {
const onchainPreview = await buildPublishDropOnchainPreview({
authorization: auth.authorization,
walletAddress: auth.walletAddress,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: payload.dropID,
isPaused: typeof payload.isPaused === "boolean" ? payload.isPaused : undefined,
preRevealIPFSPollIntervalMs: payload.preRevealIPFSPollIntervalMs,
preRevealIPFSTimeoutMs: payload.preRevealIPFSTimeoutMs
});
console.log(JSON.stringify(buildPublishDropDryRunPreview(payload, { onchainPreview }), null, 2));
return;
}
const result = await publishDropFlow(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress,
rpcUrl: await getRpcUrlForChainMId(payload.chainMId),
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: payload.dropID,
isPaused: typeof payload.isPaused === "boolean" ? payload.isPaused : undefined,
getSettingsPollIntervalMs: payload.getSettingsPollIntervalMs,
getSettingsTimeoutMs: payload.getSettingsTimeoutMs,
preRevealIPFSPollIntervalMs: payload.preRevealIPFSPollIntervalMs,
preRevealIPFSTimeoutMs: payload.preRevealIPFSTimeoutMs
},
{
getDropSettings: api.getDropSettings,
getPreRevealIPFS: api.getPreRevealIPFS,
getTempURL: api.getTempURL,
postDropSettings: api.postDropSettings,
postSetProjectConfig: api.postSetProjectConfig,
sendTransaction: sendEncodedTransaction,
postCallbackUpdateProjectConfig: api.postCallbackUpdateProjectConfig
}
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
slug: payload.slug ?? null,
dropUrl: payload.slug ? `https://element.market/collections/payload.slug` : null,
collectionUrl: payload.slug ? `https://element.market/collections/payload.slug` : null,
editUrl: payload.slug ? `https://element.market/collections/payload.slug/edit/drop` : null,
publishState: summarizePublishState({
published: result.published.settings.published,
isPaused: result.published.settings.isPaused
}),
publishTransactionHash: result.setProjectConfigTransaction.hash,
callbackSucceeded: result.published.callbackResponse.code === 0
},
settingsAfterPublish: summarizeSettingsSnapshot({
maxSupply: result.published.settings.maxSupply,
totalMint: result.published.settings.totalMint,
dropBeginTime: result.published.settings.dropBeginTime,
dropType: result.published.settings.dropType,
mintingType: result.published.settings.mintingType,
stages: result.published.settings.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "get-settings") {
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)));
setActiveOperationContext(command, payload);
const walletAddress = await getWalletAddressFromEnv();
const result = await api.getDropSettings(
{
chainMId: payload.chainMId,
contractAddress: payload.contractAddress
},
walletAddress
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress
},
settings: summarizeSettingsSnapshot({
maxSupply: result.data.maxSupply,
totalMint: result.data.totalMint,
dropBeginTime: result.data.dropBeginTime,
dropType: result.data.dropType,
mintingType: result.data.mintingType,
stages: result.data.stages,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
})
},
null,
2
)
);
return;
}
if (command === "post-settings") {
const rawPayload = await readJsonArg(filePath);
const resolvedChainPayload = await resolvePayloadChain(rawPayload);
const auth = await createAuthorization(resolvedChainPayload.chainMId);
const payload = await resolveDropLocator(resolvedChainPayload, {
needDropID: true,
walletAddress: auth.walletAddress
});
setActiveOperationContext(command, payload);
const settingsPayload = {
dropID: payload.dropID ?? 0,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropType: payload.dropType,
maxSupply: payload.maxSupply,
fee: payload.fee ?? 0,
feeRecipient: payload.feeRecipient ?? "",
mintingType: payload.mintingType ?? 0,
dropBeginTime: payload.dropBeginTime,
stagesUpdate: payload.stagesUpdate ?? []
};
const result = await api.postDropSettings(
auth.authorization,
settingsPayload,
auth.walletAddress
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress: auth.walletAddress,
success: result.code === 0
},
requestedSettings: summarizeSettingsSnapshot({
maxSupply: settingsPayload.maxSupply,
dropBeginTime: settingsPayload.dropBeginTime,
dropType: settingsPayload.dropType,
mintingType: settingsPayload.mintingType,
stages: settingsPayload.stagesUpdate,
availablePaymentTokens: Array.isArray(payload.paymentTokens) ? payload.paymentTokens : [],
currency: payload.currency
}),
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "get-design") {
const walletAddress = await getWalletAddressFromEnv();
const payload = await resolveDropLocator(await resolvePayloadChain(await readJsonArg(filePath)), {
needDropID: true,
walletAddress
});
setActiveOperationContext(command, payload);
const result = await api.getDropDesign(
{
dropID: payload.dropID,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress
},
walletAddress
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress,
hasDesign: Boolean(result.data)
},
design: summarizeDesignSnapshot(result.data)
},
null,
2
)
);
return;
}
if (command === "post-design") {
const rawPayload = await readJsonArg(filePath);
const resolvedChainPayload = await resolvePayloadChain(rawPayload);
const auth = await createAuthorization(resolvedChainPayload.chainMId);
const payload = await resolveDropLocator(resolvedChainPayload, {
needDropID: true,
walletAddress: auth.walletAddress
});
setActiveOperationContext(command, payload);
const designPayload = {
dropID: payload.dropID,
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropName: payload.dropName ?? "",
bannerURL: payload.bannerURL ?? "",
previewMediaExt: payload.previewMediaExt ?? [],
dropFeaturedImage: payload.dropFeaturedImage ?? "",
description: payload.description ?? "",
website: payload.website ?? "",
twitter: payload.twitter ?? "",
instagram: payload.instagram ?? "",
discord: payload.discord ?? "",
telegram: payload.telegram ?? "",
medium: payload.medium ?? "",
detailsUpdate: []
};
const result = await api.postDesign(
auth.authorization,
designPayload,
auth.walletAddress
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress: auth.walletAddress,
success: result.code === 0
},
requestedDesign: summarizeDesignSnapshot(designPayload),
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "upload-prereveal") {
const rawPayload = await readJsonArg(filePath);
const resolvedChainPayload = await resolvePayloadChain(rawPayload);
const auth = await createAuthorization(resolvedChainPayload.chainMId);
const payload = await resolveDropLocator(resolvedChainPayload);
setActiveOperationContext(command, payload);
const result = await uploadWithExistingAuthorization(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress
},
{
mode: "prereveal",
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropType: payload.dropType,
filePath: payload.filePath
},
{
getOssSignSingle: api.getOssSignSingle,
postPreReveal: api.postPreReveal,
uploadAsset: uploadSingleAsset
}
);
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress: auth.walletAddress,
uploaded: true,
publicUrl: result.publicUrls[0] ?? null
},
upload: {
sourcePath: result.uploads[0]?.sourcePath ?? null,
fileName: result.uploads[0]?.fileName ?? null,
objectKey: result.uploads[0]?.objectKey ?? null,
publicUrls: result.publicUrls
},
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "upload-design") {
const rawPayload = await readJsonArg(filePath);
const resolvedChainPayload = await resolvePayloadChain(rawPayload);
const auth = await createAuthorization(resolvedChainPayload.chainMId);
const payload = await resolveDropLocator(resolvedChainPayload, {
needDropID: true,
walletAddress: auth.walletAddress
});
setActiveOperationContext(command, payload);
const result = await uploadWithExistingAuthorization(
{
authorization: auth.authorization,
walletAddress: auth.walletAddress
},
{
mode: "design",
chainMId: payload.chainMId,
contractAddress: payload.contractAddress,
dropID: payload.dropID,
dropName: payload.dropName,
bannerFilePath: payload.bannerFilePath,
previewFilePaths: payload.previewFilePaths
},
{
getOssSignSingle: api.getOssSignSingle,
postPreReveal: api.postPreReveal,
uploadAsset: uploadSingleAsset
}
);
if (result.mode !== "design") {
throw new Error("upload-design expected design upload result");
}
const designResult = result;
console.log(
JSON.stringify(
{
summary: {
chainName: payload.chainName,
contractAddress: payload.contractAddress,
walletAddress: auth.walletAddress,
uploadedBanner: Boolean(designResult.payload.bannerURL),
previewMediaCount: designResult.payload.previewMediaExt.length
},
designUpload: {
bannerUrl: designResult.payload.bannerURL || null,
previewUrls: designResult.payload.previewMediaExt
.map((item) => item.image_url ?? "")
.filter(Boolean),
requestedDesign: summarizeDesignSnapshot(designResult.payload)
},
signingSafety: buildSigningSafetyNote()
},
null,
2
)
);
return;
}
if (command === "verify-ref-graphql") {
const result = await verifyRefGraphqlExamples();
console.log(JSON.stringify(result, null, 2));
return;
}
throw new Error(`unknown command: command`);
}
main().catch((error: unknown) => {
const message = redactKnownSecrets(error instanceof Error ? error.message : String(error));
console.error(
JSON.stringify(
{
error: message,
operationContext: activeOperationContext,
chainName: activeOperationContext.chainName ?? null,
symbol: activeOperationContext.symbol ?? null,
note:
"Verify chainName before retrying. A drop deployed on the wrong chain cannot be moved; create a new drop on the intended chain instead."
},
null,
2
)
);
process.exitCode = 1;
});
FILE:scripts/src/types.ts
export type DropType = 0 | 1;
export type DropEdition = "limited" | "open";
export type StageMode = 0 | 1;
export interface StageInput {
stageID: number;
stageName: string;
price: string;
duration: number;
maxSupplyAtThisStage: number;
maxMintedPerWallet: number;
interval: number;
stageMode: StageMode;
}
export interface CreateStageInput {
stageID?: number;
stageName: string;
price: string;
duration: number;
maxSupplyAtThisStage: number;
maxMintedPerWallet: number;
interval: number;
stageMode: StageMode;
}
export interface DropInput {
chainMId: number;
name: string;
symbol: string;
paymentToken?: string;
preReveal: string;
description: string;
dropType: DropType;
maxSupply: number;
dropBeginTime: number;
stages: StageInput[];
}
export interface CreateDropInput {
chainMId: number;
name: string;
symbol: string;
paymentToken?: string;
preReveal?: string;
previewMedia?: string[];
description?: string;
desc?: string;
website?: string;
twitter?: string;
instagram?: string;
discord?: string;
telegram?: string;
medium?: string;
dropFeaturedImage?: string;
edition?: DropEdition;
dropType?: DropType;
maxSupply?: number;
dropBeginTime?: number;
stages?: CreateStageInput[];
}
export interface CreateTokenRequest {
chainMId: number;
name: string;
symbol: string;
}
export interface ElementBlockChainIdentity {
chain: string;
chainId: string;
}
export interface ElementIdentity {
address: string;
blockChain: ElementBlockChainIdentity;
}
export interface ElementChainCollectionSummary {
id: string;
slug: string;
}
export interface ElementCollectionContractResponse {
chainCollection: ElementChainCollectionSummary | null;
}
export interface ElementCollectionSummary {
id: string;
name: string;
slug: string;
}
export interface ElementUserCollectionListItem extends ElementCollectionSummary {
imageUrl: string | null;
featuredImageUrl: string | null;
bannerImageUrl: string | null;
isVerified: boolean;
description: string | null;
stats: {
assetCount: number;
};
contracts: Array<{
sourceType: string | null;
}>;
}
export interface ElementCollectionContractInfo {
blockChain: ElementBlockChainIdentity;
address: string;
sourceType: string | null;
}
export interface ElementCollectionDetailFromEditors {
contracts: ElementCollectionContractInfo[];
id: string;
name: string;
slug: string;
description: string | null;
imageUrl: string | null;
bannerImageUrl: string | null;
featuredImageUrl: string | null;
externalUrl: string | null;
weiboUrl: string | null;
twitterUrl: string | null;
instagramUrl: string | null;
facebookUrl: string | null;
mediumUrl: string | null;
telegramUrl: string | null;
discordUrl: string | null;
categories: Array<{
id: string;
name: string;
slug: string;
}>;
paymentTokens: Array<{
id: string;
name: string;
address: string;
symbol: string;
chain: string;
chainId: string;
}>;
royalty: number;
royaltyAddress: string | null;
isVerified: boolean;
}
export interface ElementLoginInput {
identity: ElementIdentity;
message: string;
signature: string;
realm?: string;
source?: string;
}
export interface ElementCollectionEditInput {
collectionId: string;
token: string;
imageFilePath?: string;
name?: string;
slug?: string;
description?: string;
image?: unknown;
featuredImage?: unknown;
bannerImage?: unknown;
externalUrl?: string;
weiboUrl?: string;
twitterUrl?: string;
instagramUrl?: string;
facebookUrl?: string;
mediumUrl?: string;
telegramUrl?: string;
discordUrl?: string;
categories?: string[];
paymentTokens?: string[];
royalty?: number;
royaltyAddress?: string;
}
export interface EncodedTransaction {
from: string;
to: string;
value: string;
data: string;
}
export interface ElementApiResponse<T> {
code: number;
message: string;
data: T;
}
export interface OssSignSingleRequest {
chainMId: number;
contractAddress: string;
mediaType: "prereveal" | "design";
}
export interface OssSignedPostData {
accessid: string;
policy: string;
signature: string;
dir: string;
host: string;
expire?: string;
x_oss_credential?: string;
x_oss_date?: string;
security_token?: string;
callback?: string;
}
export interface PreRevealUploadPayload {
chainMId: number;
contractAddress: string;
dropType: DropType;
preRevealExt: {
image_url: string;
animation_url: string;
};
}
export interface DesignUploadPayload {
dropID: number;
chainMId?: number;
contractAddress?: string;
dropName: string;
bannerURL: string;
previewMediaExt: Array<{
image_url: string;
animation_url: string;
}>;
dropFeaturedImage: string;
description: string;
website: string;
twitter: string;
instagram: string;
discord: string;
telegram: string;
medium: string;
detailsUpdate: Array<{
detailID?: number;
template?: number;
title?: string;
description?: string;
imageURL?: string;
textAlign?: number | null;
faq?: unknown;
}>;
}
export interface CreateTokenPreflight {
walletAddress: string;
rpcUrl: string;
authorization: string;
nonce: string;
loginMessage: string;
identity: ElementIdentity;
}
export interface ExecutedTransactionReceipt {
hash: string;
blockNumber: number;
status: number;
gasUsed: string;
}
export interface ExecutedTransactionResult {
hash: string;
receipt: ExecutedTransactionReceipt;
contractAddress?: string;
}
export interface GetDropSettingsQuery {
chainMId: number;
contractAddress: string;
}
export interface GetDropSettingsStage {
stageID: number;
stageName: string;
price: string;
interval: number;
duration: number;
maxSupplyAtThisStage: number;
maxMintedPerWallet: number;
stageMode: number;
whiteListNum: number;
enableCallFromContract: boolean;
enableMintToOther: boolean;
address?: string;
}
export interface PaymentTokenInfo {
symbol?: string;
address?: string;
decimals?: number;
chain?: string;
chainId?: string;
logoUrl?: string;
}
export interface GetDropSettingsResponse {
dropID: number;
published: number;
maxSupply?: number;
feeRecipient?: string;
fee?: number;
dropBeginTime?: number;
isMinted: boolean;
dropType: DropType;
baseURI: string;
isStageQuotaSharedForWallet: boolean;
isPaused: boolean;
mintingType: number;
paymentToken?: PaymentTokenInfo;
paymentTokens: PaymentTokenInfo[];
mintFee: string;
totalMint: number;
batch: string;
batchTime: number;
stages: GetDropSettingsStage[];
}
export interface PostDropSettingsAllowList {
address: string;
buyCount: number;
}
export interface PostDropSettingsStageUpdate {
stageID: number;
stageName: string;
price: string;
interval: number;
duration: number;
maxMintedPerWallet: number;
maxSupplyAtThisStage: number;
stageMode: StageMode | null;
allowListsNew: PostDropSettingsAllowList[];
}
export interface PostDropSettingsRequest {
dropID: number;
chainMId: number;
contractAddress: string;
dropType: DropType;
maxSupply: number;
fee: number;
feeRecipient: string;
mintingType: number;
dropBeginTime: number;
stagesUpdate: PostDropSettingsStageUpdate[];
}
export interface GetDropDesignQuery {
dropID: number;
chainMId: number;
contractAddress: string;
}
export interface DropDesignDetail {
detailID: number;
template: number;
title: string;
description: string;
imageURL: string;
textAlign: number | null;
faq: unknown;
}
export interface GetDropDesignResponse {
dropID: number;
dropName: string;
bannerURL: string;
previewMedia: string[];
previewMediaExt: Array<{
image_url?: string;
animation_url?: string;
}>;
description: string;
website: string;
twitter: string;
instagram: string;
discord: string;
telegram: string;
medium: string;
dropFeaturedImage: string;
details: DropDesignDetail[];
}
export interface TempUrlMetaJson {
[key: string]: unknown;
}
export interface GetTempURLQuery {
chainMId: number;
contractAddress: string;
dropID: number;
page: number;
pageSize: number;
}
export interface GetTempURLResponse {
preReveal: {
image_url?: string;
animation_url?: string;
imageURL?: string;
animationURL?: string;
};
metaPublish: boolean;
metaDataIPFS: string;
metaJsons: TempUrlMetaJson[];
imgSum: number;
metaSum: number;
animationSum: number;
}
export interface GetPreRevealIPFSQuery {
chainMId: number;
contractAddress: string;
dropID: number;
}
export interface GetPreRevealIPFSResponse {
preRevealIPFS: string;
}
export interface CallbackUpdateProjectConfigRequest {
dropId: number;
chainMId: number;
contractAddress: string;
}
export interface SetProjectConfigStageInput {
stageID: number;
stageName?: string;
stageMode: number;
price: string;
address?: string;
duration: number;
maxSupplyAtThisStage: number;
maxMintedPerWallet: number;
interval: number;
enableCallFromContract?: boolean;
enableMintToOther?: boolean;
}
export interface SetProjectConfigRequest {
chainMId: number;
contractAddress: string;
nftAddress: string;
isPaused: boolean;
dropBeginTime: number;
maxSupply: string;
baseURI: string;
mintingType: number;
stages: SetProjectConfigStageInput[];
}
export interface ChainListPaymentToken {
ChainMId: number;
SerId: number;
TokenAddress: string;
Enable: boolean;
name: string;
symbol?: string;
icon: string;
decimal: number;
accuracy: number;
}
export interface ChainListWithGasItem {
chainMId: number;
currency: string;
tokenCount: number;
usdPrice: number;
paymentTokens: ChainListPaymentToken[];
}
export interface GetChainsWithGasResponse {
chains: ChainListWithGasItem[];
}
FILE:scripts/src/workflow/configure-drop.ts
import type { CreateStageInput, DropEdition, GetDropDesignResponse, GetDropSettingsStage, StageInput } from "../types";
import { resolveMintingTypeFromPaymentToken } from "../network/chains";
import { DEFAULT_MAX_SUPPLY, resolveDropMode } from "../drop-mode";
import { buildDropUrls, buildInitialSettingsPayload, createWorkflowLogger, runStage } from "./create-drop";
import {
buildCollectionEditPayload,
buildDisplayDesignAfterUpdate,
buildMergedDesignPayload,
hasCollectionMetadataOverride,
hasDesignOverride
} from "./design-payloads";
import { uploadWithExistingAuthorization } from "./uploads";
import type {
ChainListPaymentToken,
DesignUploadPayload,
ElementApiResponse,
ElementCollectionDetailFromEditors,
ElementCollectionEditInput,
ElementCollectionSummary,
GetDropSettingsResponse,
OssSignedPostData,
PostDropSettingsRequest,
PreRevealUploadPayload
} from "../types";
export interface ConfigureDropFlowInput {
chainMId: number;
authorization: string;
walletAddress: string;
contractAddress: string;
slug?: string;
name?: string;
symbol?: string;
paymentToken?: string;
paymentTokens?: ChainListPaymentToken[];
preReveal?: string;
previewMedia?: string[];
description?: string;
edition?: DropEdition;
dropType?: 0 | 1;
maxSupply?: number;
dropBeginTime?: number;
stages?: CreateStageInput[];
bannerFilePath?: string;
previewFilePaths?: string[];
website?: string;
twitter?: string;
instagram?: string;
discord?: string;
telegram?: string;
medium?: string;
dropFeaturedImage?: string;
}
export interface ConfigureDropFlowDeps {
uploadWithExistingAuthorization: typeof uploadWithExistingAuthorization;
getDropSettings: (
query: { chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropSettingsResponse>>;
getDropDesign: (
query: { dropID: number; chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropDesignResponse>>;
postDropSettings: (
authorization: string,
body: PostDropSettingsRequest,
walletAddress: string
) => Promise<ElementApiResponse<null>>;
getOssSignSingle: (
authorization: string,
query: { chainMId: number; contractAddress: string; mediaType: "prereveal" | "design" },
walletAddress?: string
) => Promise<ElementApiResponse<OssSignedPostData>>;
postPreReveal: (
authorization: string,
body: PreRevealUploadPayload,
walletAddress?: string
) => Promise<ElementApiResponse<null>>;
postDesign: (
authorization: string,
body: DesignUploadPayload,
walletAddress?: string
) => Promise<ElementApiResponse<null>>;
getMutateToken: (authorization?: string) => Promise<string>;
getCollectionDetailFromEditors: (
slug: string,
authorization?: string
) => Promise<ElementCollectionDetailFromEditors>;
collectionEdit: (
input: ElementCollectionEditInput,
authorization?: string
) => Promise<ElementCollectionSummary>;
uploadAsset: (input: {
filePath: string;
fileName: string;
oss: OssSignedPostData;
}) => Promise<{
sourcePath: string;
fileName: string;
objectKey: string;
publicUrl: string;
}>;
}
const DEFAULT_STAGE_DURATION_SECONDS = 3 * 24 * 60 * 60;
const DEFAULT_STAGE_NAME = "Public";
const DEFAULT_STAGE_PRICE = "0";
const DEFAULT_STAGE_INTERVAL = 0;
const DEFAULT_STAGE_MAX_MINTED_PER_WALLET = 1;
const DEFAULT_STAGE_ID = 256;
function hasSettingsOverride(input: ConfigureDropFlowInput): boolean {
return Boolean(
input.preReveal !== undefined ||
input.edition !== undefined ||
input.dropType !== undefined ||
input.maxSupply !== undefined ||
input.dropBeginTime !== undefined ||
input.paymentToken !== undefined ||
(input.stages !== undefined && input.stages.length >= 0)
);
}
function defaultDropBeginTime(): number {
return Math.floor(Date.now() / 1000) + 24 * 60 * 60;
}
function assignStageIds(stages: CreateStageInput[]): StageInput[] {
return stages.map((stage, index) => ({
...stage,
stageID: DEFAULT_STAGE_ID + index
}));
}
function buildDefaultStage(maxSupply: number): StageInput {
return {
stageID: DEFAULT_STAGE_ID,
stageName: DEFAULT_STAGE_NAME,
price: DEFAULT_STAGE_PRICE,
duration: DEFAULT_STAGE_DURATION_SECONDS,
maxSupplyAtThisStage: maxSupply,
maxMintedPerWallet: DEFAULT_STAGE_MAX_MINTED_PER_WALLET,
interval: DEFAULT_STAGE_INTERVAL,
stageMode: 0
};
}
export async function previewConfigureDrop(input: {
authorization: string;
walletAddress: string;
chainMId: number;
contractAddress: string;
slug?: string;
patch: Omit<ConfigureDropFlowInput, "authorization" | "walletAddress" | "chainMId" | "contractAddress" | "slug">;
}, deps: Pick<ConfigureDropFlowDeps, "getDropSettings" | "getDropDesign" | "getMutateToken" | "getCollectionDetailFromEditors">) {
const logger = createWorkflowLogger();
const mergedInput: ConfigureDropFlowInput = {
chainMId: input.chainMId,
contractAddress: input.contractAddress,
authorization: input.authorization,
walletAddress: input.walletAddress,
slug: input.slug,
...input.patch
};
const currentSettingsResponse = await runStage(logger, "previewUpdate:getCurrentSettings", () =>
deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
)
);
const currentSettings = currentSettingsResponse.data;
const shouldUpdateSettings = hasSettingsOverride(mergedInput);
const settingsPayload = shouldUpdateSettings
? buildMergedSettingsPayload({
current: currentSettings,
patch: mergedInput,
contractAddress: input.contractAddress
})
: null;
const shouldUpdateDesign = hasDesignOverride(mergedInput);
const currentDesignResponse =
currentSettings.dropID > 0 && shouldUpdateDesign
? await runStage(logger, "previewUpdate:getCurrentDesign", () =>
deps.getDropDesign(
{
dropID: currentSettings.dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
)
)
: null;
const currentDesign = currentDesignResponse?.data ?? null;
const designPayload =
shouldUpdateDesign
? buildMergedDesignPayload({
current: currentDesign,
patch: mergedInput,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: currentSettings.dropID,
uploadedBannerUrl: null,
uploadedPreviewUrls: undefined
})
: null;
const collectionEditPayload =
input.slug && hasCollectionMetadataOverride(mergedInput)
? buildCollectionEditPayload({
current: await runStage(logger, "previewUpdate:getCurrentCollectionDetail", () =>
deps.getCollectionDetailFromEditors(input.slug!, input.authorization)
),
patch: mergedInput,
token: await runStage(logger, "previewUpdate:getMutateToken", () => deps.getMutateToken(input.authorization))
})
: null;
return {
contractAddress: input.contractAddress,
chainMId: input.chainMId,
slug: input.slug ?? null,
urls: input.slug ? buildDropUrls(input.slug) : null,
currentSettings: currentSettingsResponse,
currentDesign: currentDesignResponse,
settingsPayload,
designPayload,
collectionEditPayload,
summary: {
dropID: currentSettings.dropID,
willReadCurrentSettings: true,
willReadCurrentDesign: shouldUpdateDesign,
willUpdateSettings: shouldUpdateSettings,
willUpdatePreReveal: Boolean(mergedInput.preReveal),
willUpdateDesign: shouldUpdateDesign,
willUpdateCollectionProfile: Boolean(collectionEditPayload),
willUploadImages: Boolean(
mergedInput.preReveal ??
mergedInput.bannerFilePath ??
(mergedInput.previewFilePaths && mergedInput.previewFilePaths.length > 0)
),
patchKeys: Object.keys(mergedInput).filter((key) => {
const value = mergedInput[key as keyof ConfigureDropFlowInput];
return value !== undefined && !["authorization", "walletAddress", "chainMId", "contractAddress", "slug"].includes(key);
}),
nextSettings: settingsPayload
? {
dropType: settingsPayload.dropType,
maxSupply: settingsPayload.maxSupply,
dropBeginTime: settingsPayload.dropBeginTime,
mintingType: settingsPayload.mintingType,
stageCount: settingsPayload.stagesUpdate.length
}
: null,
nextDesign: designPayload
? {
dropName: designPayload.dropName,
bannerURL: designPayload.bannerURL,
previewCount: designPayload.previewMediaExt.length,
description: designPayload.description,
website: designPayload.website,
twitter: designPayload.twitter,
instagram: designPayload.instagram,
discord: designPayload.discord,
telegram: designPayload.telegram,
medium: designPayload.medium
}
: null,
nextCollectionProfile: collectionEditPayload
? {
externalUrl: collectionEditPayload.externalUrl ?? null,
twitterUrl: collectionEditPayload.twitterUrl ?? null,
instagramUrl: collectionEditPayload.instagramUrl ?? null,
discordUrl: collectionEditPayload.discordUrl ?? null,
telegramUrl: collectionEditPayload.telegramUrl ?? null,
mediumUrl: collectionEditPayload.mediumUrl ?? null
}
: null
}
};
}
function mapCurrentStages(stages: GetDropSettingsStage[] | null | undefined): StageInput[] {
if (!stages || stages.length === 0) {
return [];
}
return stages.map((stage) => ({
stageID: stage.stageID,
stageName: stage.stageName,
price: stage.price,
duration: stage.duration,
maxSupplyAtThisStage: stage.maxSupplyAtThisStage,
maxMintedPerWallet: stage.maxMintedPerWallet,
interval: stage.interval,
stageMode: (stage.stageMode === 1 ? 1 : 0) as 0 | 1
}));
}
function buildMergedSettingsPayload(input: {
current: GetDropSettingsResponse;
patch: ConfigureDropFlowInput;
contractAddress: string;
}): PostDropSettingsRequest {
const { dropType, maxSupply } = resolveDropMode({
requestedEdition: input.patch.edition,
requestedDropType: input.patch.dropType,
requestedMaxSupply: input.patch.maxSupply,
fallbackDropType: input.current.dropType ?? undefined,
fallbackMaxSupply: input.current.maxSupply ?? DEFAULT_MAX_SUPPLY
});
const stages =
input.patch.stages && input.patch.stages.length > 0
? assignStageIds(input.patch.stages)
: (() => {
const currentStages = mapCurrentStages(input.current.stages);
return currentStages.length > 0 ? currentStages : [buildDefaultStage(maxSupply)];
})();
return {
dropID: input.current.dropID ?? 0,
chainMId: input.patch.chainMId,
contractAddress: input.contractAddress,
dropType,
maxSupply,
fee: input.current.fee ?? 0,
feeRecipient: input.current.feeRecipient ?? "",
mintingType: resolveMintingTypeFromPaymentToken({
paymentToken: input.patch.paymentToken,
availablePaymentTokens: input.patch.paymentTokens,
fallbackMintingType: input.current.mintingType ?? 0
}),
dropBeginTime: input.patch.dropBeginTime ?? input.current.dropBeginTime ?? defaultDropBeginTime(),
stagesUpdate: stages.map((stage) => ({
stageID: stage.stageID,
stageName: stage.stageName,
price: stage.price,
interval: stage.interval,
duration: stage.duration,
maxMintedPerWallet: stage.maxMintedPerWallet,
maxSupplyAtThisStage: stage.maxSupplyAtThisStage,
stageMode: stage.stageMode,
allowListsNew: []
}))
};
}
function hasCurrentBanner(current: GetDropDesignResponse | null): boolean {
return Boolean(current?.bannerURL?.trim());
}
function hasCurrentPreviewMedia(current: GetDropDesignResponse | null): boolean {
return Boolean(
current?.previewMediaExt?.some((item) => item.image_url?.trim() || item.animation_url?.trim()) ||
current?.previewMedia?.some((item) => {
if (typeof item === "string") {
return item.trim().length > 0;
}
if (item && typeof item === "object") {
const record = item as Record<string, unknown>;
return Boolean(
(typeof record.image_url === "string" && record.image_url.trim()) ||
(typeof record.imageURL === "string" && record.imageURL.trim()) ||
(typeof record.animation_url === "string" && record.animation_url.trim()) ||
(typeof record.animationURL === "string" && record.animationURL.trim())
);
}
return false;
})
);
}
export function resolveDesignAssetUrlsForUpdate(input: {
currentDesign: GetDropDesignResponse | null;
preRevealUrl?: string | null;
explicitBannerProvided: boolean;
explicitPreviewProvided: boolean;
uploadedBannerUrl?: string | null;
uploadedPreviewUrls?: string[];
}): { uploadedBannerUrl: string | null; uploadedPreviewUrls: string[] | undefined } {
const preRevealUrl = input.preRevealUrl?.trim();
const uploadedPreviewUrls =
input.uploadedPreviewUrls && input.uploadedPreviewUrls.length > 0
? input.uploadedPreviewUrls
: !input.explicitPreviewProvided && preRevealUrl && !hasCurrentPreviewMedia(input.currentDesign)
? [preRevealUrl]
: undefined;
return {
uploadedBannerUrl:
input.uploadedBannerUrl ??
(!input.explicitBannerProvided && preRevealUrl && !hasCurrentBanner(input.currentDesign) ? preRevealUrl : null),
uploadedPreviewUrls
};
}
export async function configureDropFlow(input: ConfigureDropFlowInput, deps: ConfigureDropFlowDeps) {
const logger = createWorkflowLogger();
const auth = {
authorization: input.authorization,
walletAddress: input.walletAddress
};
const preRevealPath = input.preReveal;
const currentSettingsResponse = await runStage(logger, "getCurrentSettings", () =>
deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
auth.walletAddress
)
);
const currentSettings = currentSettingsResponse.data;
const currentDropID = currentSettings.dropID ?? 0;
const shouldUpdateSettings = hasSettingsOverride(input);
const shouldUpdateDesign = hasDesignOverride(input);
const shouldUpdateCollectionMetadata = Boolean(input.slug && hasCollectionMetadataOverride(input));
const settingsPayload = shouldUpdateSettings
? buildMergedSettingsPayload({
current: currentSettings,
patch: input,
contractAddress: input.contractAddress
})
: null;
const settingsResponse = settingsPayload
? await runStage(logger, "postSettings", () =>
deps.postDropSettings(auth.authorization, settingsPayload, auth.walletAddress)
)
: null;
const settingsAfterConfigure =
settingsPayload
? await runStage(logger, "getSettingsAfterConfigure", () =>
deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
auth.walletAddress
)
)
: currentSettingsResponse;
const dropID = settingsAfterConfigure.data.dropID ?? currentDropID;
const preRevealUpload = preRevealPath
? await runStage(logger, "uploadPreReveal", () =>
deps.uploadWithExistingAuthorization(
auth,
{
mode: "prereveal",
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropType: resolveDropMode({
requestedEdition: input.edition,
requestedDropType: input.dropType,
requestedMaxSupply: input.maxSupply,
fallbackDropType: currentSettings.dropType ?? undefined,
fallbackMaxSupply: currentSettings.maxSupply ?? DEFAULT_MAX_SUPPLY
}).dropType,
filePath: preRevealPath
},
{
getOssSignSingle: deps.getOssSignSingle,
postPreReveal: deps.postPreReveal,
uploadAsset: deps.uploadAsset
}
)
)
: null;
if ((shouldUpdateDesign || input.bannerFilePath || (input.previewFilePaths && input.previewFilePaths.length > 0)) && !(dropID > 0)) {
throw new Error(`dropID is missing for design update on input.contractAddress`);
}
const currentDesignResponse =
dropID > 0 && shouldUpdateDesign
? await runStage(logger, "getCurrentDesign", () =>
deps.getDropDesign(
{
dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
auth.walletAddress
)
)
: null;
const currentDesign = currentDesignResponse?.data ?? null;
const assetDesignUpload =
input.bannerFilePath ||
(input.previewMedia && input.previewMedia.length > 0) ||
(input.previewFilePaths && input.previewFilePaths.length > 0)
? await runStage(logger, "uploadDesignAssets", () => {
const designBannerFilePath = input.bannerFilePath;
const designPreviewFilePaths = input.previewMedia?.length
? input.previewMedia
: input.previewFilePaths?.length
? input.previewFilePaths
: [];
if (!designBannerFilePath && designPreviewFilePaths.length === 0) {
throw new Error("design asset update requires at least one banner or preview source");
}
return deps.uploadWithExistingAuthorization(
auth,
{
mode: "design",
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID,
dropName: input.name ?? currentDesign?.dropName ?? "",
bannerFilePath: designBannerFilePath,
previewFilePaths: designPreviewFilePaths
},
{
getOssSignSingle: deps.getOssSignSingle,
postPreReveal: deps.postPreReveal,
uploadAsset: deps.uploadAsset
}
);
})
: null;
const designAssetUrls = resolveDesignAssetUrlsForUpdate({
currentDesign,
preRevealUrl: preRevealUpload?.publicUrls[0],
explicitBannerProvided: Boolean(input.bannerFilePath),
explicitPreviewProvided: Boolean(
(input.previewMedia && input.previewMedia.length > 0) ||
(input.previewFilePaths && input.previewFilePaths.length > 0)
),
uploadedBannerUrl: assetDesignUpload?.mode === "design" ? assetDesignUpload.payload.bannerURL : null,
uploadedPreviewUrls:
assetDesignUpload?.mode === "design"
? assetDesignUpload.payload.previewMediaExt.map((item) => item.image_url ?? "").filter(Boolean)
: undefined
});
const designPayload =
shouldUpdateDesign
? buildMergedDesignPayload({
current: currentDesign,
patch: input,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID,
uploadedBannerUrl: designAssetUrls.uploadedBannerUrl,
uploadedPreviewUrls: designAssetUrls.uploadedPreviewUrls
})
: null;
const designResponse =
designPayload
? await runStage(logger, "postDesign", () =>
deps.postDesign(auth.authorization, designPayload, auth.walletAddress)
)
: null;
const designBannerUrl = designPayload?.bannerURL ?? null;
const collectionEditPayload =
shouldUpdateCollectionMetadata
? buildCollectionEditPayload({
current: await runStage(logger, "getCurrentCollectionDetail", () =>
deps.getCollectionDetailFromEditors(input.slug!, auth.authorization)
),
patch: input,
token: await runStage(logger, "getMutateToken", () => deps.getMutateToken(auth.authorization))
})
: null;
const collectionEditResponse =
collectionEditPayload
? await runStage(logger, "collectionEdit", () =>
deps.collectionEdit(collectionEditPayload, auth.authorization)
)
: null;
const urls = input.slug ? buildDropUrls(input.slug) : null;
return {
currentSettings,
contractAddress: input.contractAddress,
currentSettingsResponse,
settingsPayload,
settingsResponse,
settingsAfterConfigure,
dropID,
preRevealUpload,
currentDesignResponse,
designPayload,
designResponse,
collectionEditPayload,
collectionEditResponse,
designUpload: assetDesignUpload,
designBannerUrl,
slug: input.slug ?? null,
urls
};
}
FILE:scripts/src/workflow/post-create-collection.ts
import { waitForCollectionContract } from "./wait-collection-contract";
import { buildCollectionEditPayload, type CollectionMetadataPatch } from "./design-payloads";
import type {
ElementChainCollectionSummary,
ElementCollectionDetailFromEditors,
ElementCollectionEditInput,
ElementCollectionSummary
} from "../types";
export interface PostCreateCollectionInput {
chainMId: number;
contractAddress: string;
authorization?: string;
imageFilePath?: string;
collectionMetadata?: CollectionMetadataPatch;
pollIntervalMs?: number;
timeoutMs?: number;
}
export interface PostCreateCollectionDeps {
getCollectionContract: (input: {
address: string;
blockChain: {
chain: string;
chainId: string;
};
}) => Promise<ElementChainCollectionSummary | null>;
getMutateToken: (authorization?: string) => Promise<string>;
getCollectionDetailFromEditors: (
slug: string,
authorization?: string
) => Promise<ElementCollectionDetailFromEditors>;
collectionEdit: (input: ElementCollectionEditInput, authorization?: string) => Promise<ElementCollectionSummary>;
sleep?: (ms: number) => Promise<void>;
now?: () => number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
export async function postCreateCollectionFlow(
input: PostCreateCollectionInput,
deps: PostCreateCollectionDeps
) {
const collectionContract = await waitForCollectionContract(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
pollIntervalMs: input.pollIntervalMs,
timeoutMs: input.timeoutMs
},
{
getCollectionContract: deps.getCollectionContract,
sleep: deps.sleep,
now: deps.now,
logger: deps.logger
}
);
deps.logger?.("postCreateCollection:get mutate token", {
contractAddress: input.contractAddress
});
const mutateToken = await deps.getMutateToken(input.authorization);
deps.logger?.("postCreateCollection:get detail", {
slug: collectionContract.collection.slug
});
const collectionDetail = await deps.getCollectionDetailFromEditors(
collectionContract.collection.slug,
input.authorization
);
deps.logger?.("postCreateCollection:collection edit", {
collectionId: collectionContract.collection.id,
slug: collectionContract.collection.slug
});
const collectionEdit = await deps.collectionEdit(
buildCollectionEditPayload({
current: collectionDetail,
patch: input.collectionMetadata ?? {},
token: mutateToken,
imageFilePath: input.imageFilePath
}),
input.authorization
);
return {
collectionContract,
mutateToken,
collectionDetail,
collectionEdit
};
}
FILE:scripts/src/workflow/create-token.ts
import { buildElementAuthorization, deriveWalletAddress } from "../auth/jwt";
import { getRequiredWalletPrivateKey } from "../env";
import { getRpcUrlForChainMId } from "../network/rpc";
import { sendEncodedTransaction } from "../network/transaction";
import { normalizeCreateDropInput } from "../schema";
import type {
CreateDropInput,
CreateTokenPreflight,
ElementApiResponse,
EncodedTransaction,
ExecutedTransactionResult
} from "../types";
export interface CreateTokenFlowDeps {
deriveAddress: typeof deriveWalletAddress;
resolveRpcUrl: typeof getRpcUrlForChainMId;
createAuthorization: (input: {
privateKey: string;
walletAddress?: string;
chainMId: number;
}) => Promise<{
authorization: string;
nonce: string;
message: string;
identity: {
address: string;
blockChain: {
chain: string;
chainId: string;
};
};
}>;
postCreateToken: (
authorization: string,
body: { chainMId: number; name: string; symbol: string },
walletAddress?: string
) => Promise<ElementApiResponse<EncodedTransaction>>;
sendTransaction: typeof sendEncodedTransaction;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
export async function createTokenFlow(input: CreateDropInput, deps: CreateTokenFlowDeps) {
const parsed = normalizeCreateDropInput(input);
const privateKey = getRequiredWalletPrivateKey();
const walletAddress = (await deps.deriveAddress({ privateKey })).toLowerCase();
const rpcUrl = await deps.resolveRpcUrl(parsed.chainMId);
const auth = await deps.createAuthorization({
privateKey,
walletAddress,
chainMId: parsed.chainMId
});
const response = await deps.postCreateToken(
auth.authorization,
{
chainMId: parsed.chainMId,
name: parsed.name,
symbol: parsed.symbol
},
walletAddress
);
if (response.code !== 0) {
throw new Error(`createToken failed: response.message`);
}
const transaction = await deps.sendTransaction({
rpcUrl,
transaction: response.data,
logger: deps.logger
});
return {
...response,
transaction: transaction satisfies ExecutedTransactionResult,
preflight: {
walletAddress,
rpcUrl,
authorization: auth.authorization,
nonce: auth.nonce,
loginMessage: auth.message,
identity: auth.identity
} satisfies CreateTokenPreflight
};
}
FILE:scripts/src/workflow/publish-drop.ts
import type {
CallbackUpdateProjectConfigRequest,
ElementApiResponse,
EncodedTransaction,
ExecutedTransactionResult,
GetDropSettingsResponse,
GetPreRevealIPFSResponse,
GetTempURLResponse,
PostDropSettingsRequest,
StageMode,
SetProjectConfigRequest
} from "../types";
export interface WaitForPreRevealIPFSInput {
chainMId: number;
contractAddress: string;
dropID: number;
walletAddress: string;
pollIntervalMs?: number;
timeoutMs?: number;
}
export interface WaitForPreRevealIPFSDeps {
getPreRevealIPFS: (
query: { chainMId: number; contractAddress: string; dropID: number },
walletAddress: string
) => Promise<ElementApiResponse<GetPreRevealIPFSResponse>>;
sleep?: (ms: number) => Promise<void>;
now?: () => number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
export interface WaitForPublishedInput {
chainMId: number;
contractAddress: string;
dropID: number;
walletAddress: string;
expectedPublished?: number;
expectedIsPaused?: boolean;
pollIntervalMs?: number;
timeoutMs?: number;
}
export interface WaitForPublishedDeps {
postCallbackUpdateProjectConfig: (
body: CallbackUpdateProjectConfigRequest
) => Promise<ElementApiResponse<null>>;
getDropSettings: (
query: { chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropSettingsResponse>>;
sleep?: (ms: number) => Promise<void>;
now?: () => number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
export interface ResolvePublishPreRevealInput {
authorization: string;
walletAddress: string;
chainMId: number;
contractAddress: string;
dropID: number;
pollIntervalMs?: number;
timeoutMs?: number;
}
export interface ResolvePublishPreRevealDeps {
getTempURL: (
authorization: string,
query: { chainMId: number; contractAddress: string; dropID: number; page: number; pageSize: number },
walletAddress: string
) => Promise<ElementApiResponse<GetTempURLResponse>>;
getPreRevealIPFS: (
query: { chainMId: number; contractAddress: string; dropID: number },
walletAddress: string
) => Promise<ElementApiResponse<GetPreRevealIPFSResponse>>;
sleep?: (ms: number) => Promise<void>;
now?: () => number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
export interface PublishDropFlowInput {
authorization: string;
walletAddress: string;
rpcUrl: string;
chainMId: number;
contractAddress: string;
dropID: number;
isPaused?: boolean;
getSettingsPollIntervalMs?: number;
getSettingsTimeoutMs?: number;
preRevealIPFSPollIntervalMs?: number;
preRevealIPFSTimeoutMs?: number;
}
export interface PublishDropFlowDeps {
getDropSettings: (
query: { chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropSettingsResponse>>;
getPreRevealIPFS: (
query: { chainMId: number; contractAddress: string; dropID: number },
walletAddress: string
) => Promise<ElementApiResponse<GetPreRevealIPFSResponse>>;
getTempURL: (
authorization: string,
query: { chainMId: number; contractAddress: string; dropID: number; page: number; pageSize: number },
walletAddress: string
) => Promise<ElementApiResponse<GetTempURLResponse>>;
postDropSettings: (
authorization: string,
body: PostDropSettingsRequest,
walletAddress: string
) => Promise<ElementApiResponse<null>>;
postSetProjectConfig: (
authorization: string,
body: SetProjectConfigRequest,
walletAddress: string
) => Promise<ElementApiResponse<EncodedTransaction>>;
sendTransaction: (input: {
rpcUrl: string;
transaction: EncodedTransaction;
waitConfirmations?: number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}) => Promise<ExecutedTransactionResult>;
postCallbackUpdateProjectConfig: (
body: CallbackUpdateProjectConfigRequest
) => Promise<ElementApiResponse<null>>;
sleep?: (ms: number) => Promise<void>;
now?: () => number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
async function defaultSleep(ms: number): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, ms));
}
export function extractPreRevealImageUrl(tempURL: GetTempURLResponse | null | undefined): string {
return tempURL?.preReveal?.image_url?.trim() ?? tempURL?.preReveal?.imageURL?.trim() ?? "";
}
export function extractPreRevealAnimationUrl(tempURL: GetTempURLResponse | null | undefined): string {
return tempURL?.preReveal?.animation_url?.trim() ?? tempURL?.preReveal?.animationURL?.trim() ?? "";
}
export function assertPreRevealImageUrlExists(input: {
contractAddress: string;
preRevealImageUrl: string;
}) {
if (!input.preRevealImageUrl) {
throw new Error(
`publish requires a configured prereveal image URL for input.contractAddress; ` +
`the current prereveal media resource is empty, so rerun upload/preReveal and retry publish`
);
}
}
export function buildPostDropSettingsPayloadFromSettings(input: {
settings: GetDropSettingsResponse;
chainMId: number;
contractAddress: string;
}): PostDropSettingsRequest {
return {
dropID: input.settings.dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropType: input.settings.dropType,
maxSupply: input.settings.maxSupply ?? 0,
fee: input.settings.fee ?? 0,
feeRecipient: input.settings.feeRecipient ?? "",
mintingType: input.settings.mintingType,
dropBeginTime: input.settings.dropBeginTime ?? 0,
stagesUpdate: input.settings.stages.map((stage) => ({
stageID: stage.stageID,
stageName: stage.stageName,
price: stage.price,
interval: stage.interval,
duration: stage.duration,
maxMintedPerWallet: stage.maxMintedPerWallet,
maxSupplyAtThisStage: stage.maxSupplyAtThisStage,
stageMode: stage.stageMode as StageMode | null,
allowListsNew: []
}))
};
}
export function buildSetProjectConfigPayload(input: {
settings: GetDropSettingsResponse;
chainMId: number;
contractAddress: string;
preRevealIPFS: string;
isPaused?: boolean;
}): SetProjectConfigRequest {
return {
isPaused: input.isPaused ?? false,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
nftAddress: input.contractAddress,
dropBeginTime: input.settings.dropBeginTime ?? 0,
maxSupply: String(input.settings.maxSupply ?? 0),
baseURI: input.preRevealIPFS,
mintingType: input.settings.mintingType,
stages: input.settings.stages.map((stage) => ({
stageID: stage.stageID,
stageName: stage.stageName,
stageMode: stage.stageMode,
price: stage.price,
address: stage.address ?? "0x0000000000000000000000000000000000000000",
duration: stage.duration,
maxSupplyAtThisStage: stage.maxSupplyAtThisStage,
maxMintedPerWallet: stage.maxMintedPerWallet,
interval: stage.interval,
enableCallFromContract: stage.enableCallFromContract,
enableMintToOther: stage.enableMintToOther
}))
};
}
export async function waitForPreRevealIPFS(
input: WaitForPreRevealIPFSInput,
deps: WaitForPreRevealIPFSDeps
) {
const pollIntervalMs = input.pollIntervalMs ?? 5_000;
const timeoutMs = input.timeoutMs ?? 10 * 60 * 1000;
const sleep = deps.sleep ?? defaultSleep;
const now = deps.now ?? Date.now;
const startedAt = now();
let attempts = 0;
while (true) {
attempts += 1;
deps.logger?.("preRevealIPFS:poll", {
attempt: attempts,
dropID: input.dropID,
elapsedMs: now() - startedAt
});
const response = await deps.getPreRevealIPFS(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID
},
input.walletAddress
);
const preRevealIPFS = response.data?.preRevealIPFS ?? "";
if (preRevealIPFS) {
deps.logger?.("preRevealIPFS:resolved", {
attempt: attempts,
dropID: input.dropID,
preRevealIPFS,
elapsedMs: now() - startedAt
});
return {
preRevealIPFS,
attempts,
elapsedMs: now() - startedAt
};
}
if (now() - startedAt >= timeoutMs) {
throw new Error(
`preRevealIPFS timed out after attempts attempts (timeoutMsms) for drop input.dropID; ` +
`if prereveal OSS to IPFS promotion is stuck, run upload/preReveal again and retry publish`
);
}
await sleep(pollIntervalMs);
}
}
export async function resolvePublishPreRevealIPFS(
input: ResolvePublishPreRevealInput,
deps: ResolvePublishPreRevealDeps
) {
deps.logger?.("publish:prereveal:read-temp-url", {
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID
});
const tempURLResponse = await deps.getTempURL(
input.authorization,
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID,
page: 1,
pageSize: 1
},
input.walletAddress
);
assertPreRevealImageUrlExists({
contractAddress: input.contractAddress,
preRevealImageUrl: extractPreRevealImageUrl(tempURLResponse.data)
});
deps.logger?.("publish:prereveal:trigger-and-poll-ipfs", {
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID
});
const preRevealIPFS = await waitForPreRevealIPFS(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID,
walletAddress: input.walletAddress,
pollIntervalMs: input.pollIntervalMs,
timeoutMs: input.timeoutMs
},
{
getPreRevealIPFS: deps.getPreRevealIPFS,
sleep: deps.sleep,
now: deps.now,
logger: deps.logger
}
);
return {
tempURL: tempURLResponse.data,
preRevealIPFS
};
}
export async function waitForPublishedSettings(
input: WaitForPublishedInput,
deps: WaitForPublishedDeps
) {
const pollIntervalMs = input.pollIntervalMs ?? 5_000;
const timeoutMs = input.timeoutMs ?? 10 * 60 * 1000;
const expectedPublished = input.expectedPublished ?? 1;
const expectedIsPaused = input.expectedIsPaused;
const sleep = deps.sleep ?? defaultSleep;
const now = deps.now ?? Date.now;
const startedAt = now();
let attempts = 0;
while (true) {
attempts += 1;
deps.logger?.("publishedSettings:callback", {
attempt: attempts,
dropID: input.dropID,
contractAddress: input.contractAddress,
elapsedMs: now() - startedAt
});
const callbackResponse = await deps.postCallbackUpdateProjectConfig({
dropId: input.dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress
});
deps.logger?.("publishedSettings:poll", {
attempt: attempts,
dropID: input.dropID,
contractAddress: input.contractAddress,
callbackCode: callbackResponse.code,
elapsedMs: now() - startedAt
});
const response = await deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
);
const publishedMatches = (response.data?.published ?? 0) === expectedPublished;
const pausedMatches =
expectedIsPaused === undefined ? true : (response.data?.isPaused ?? false) === expectedIsPaused;
if (publishedMatches && pausedMatches) {
const finalSettingsResponse = await deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
);
deps.logger?.("publishedSettings:resolved", {
attempt: attempts,
dropID: input.dropID,
contractAddress: input.contractAddress,
expectedPublished,
expectedIsPaused,
published: finalSettingsResponse.data?.published ?? 0,
isPaused: finalSettingsResponse.data?.isPaused ?? false,
elapsedMs: now() - startedAt
});
return {
settings: finalSettingsResponse.data,
callbackResponse,
attempts,
elapsedMs: now() - startedAt
};
}
if (now() - startedAt >= timeoutMs) {
throw new Error(
`published settings timed out after attempts attempts (timeoutMsms) for input.contractAddress; ` +
`expected published=expectedPublished` +
`` and isPaused=${expectedIsPaused`}, ` +
`got published=response.data?.published ?? 0 and isPaused=response.data?.isPaused ?? false`
);
}
await sleep(pollIntervalMs);
}
}
export async function publishDropFlow(
input: PublishDropFlowInput,
deps: PublishDropFlowDeps
) {
deps.logger?.("publish:start", {
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID
});
const settingsBeforePublishResponse = await deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
);
const settingsBeforePublish = settingsBeforePublishResponse.data;
const preRevealResolution = await resolvePublishPreRevealIPFS(
{
authorization: input.authorization,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID,
walletAddress: input.walletAddress,
pollIntervalMs: input.preRevealIPFSPollIntervalMs,
timeoutMs: input.preRevealIPFSTimeoutMs
},
{
getTempURL: deps.getTempURL,
getPreRevealIPFS: deps.getPreRevealIPFS,
sleep: deps.sleep,
now: deps.now,
logger: deps.logger
}
);
const postSettingsPayload = buildPostDropSettingsPayloadFromSettings({
settings: settingsBeforePublish,
chainMId: input.chainMId,
contractAddress: input.contractAddress
});
const postSettingsResponse = await deps.postDropSettings(
input.authorization,
postSettingsPayload,
input.walletAddress
);
const setProjectConfigPayload = buildSetProjectConfigPayload({
settings: settingsBeforePublish,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
preRevealIPFS: preRevealResolution.preRevealIPFS.preRevealIPFS,
isPaused: input.isPaused
});
const setProjectConfigResponse = await deps.postSetProjectConfig(
input.authorization,
setProjectConfigPayload,
input.walletAddress
);
if (setProjectConfigResponse.code !== 0) {
throw new Error(`setProjectConfig failed: setProjectConfigResponse.message`);
}
const setProjectConfigTransaction = await deps.sendTransaction({
rpcUrl: input.rpcUrl,
transaction: setProjectConfigResponse.data,
logger: deps.logger
});
const callbackPayload = {
dropId: input.dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress
};
const published = await waitForPublishedSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID,
walletAddress: input.walletAddress,
expectedPublished: 1,
expectedIsPaused: setProjectConfigPayload.isPaused,
pollIntervalMs: input.getSettingsPollIntervalMs,
timeoutMs: input.getSettingsTimeoutMs
},
{
postCallbackUpdateProjectConfig: deps.postCallbackUpdateProjectConfig,
getDropSettings: deps.getDropSettings,
sleep: deps.sleep,
now: deps.now,
logger: deps.logger
}
);
return {
settingsBeforePublish,
tempURLBeforePublish: preRevealResolution.tempURL,
preRevealIPFS: preRevealResolution.preRevealIPFS,
postSettingsPayload,
postSettingsResponse,
setProjectConfigPayload,
setProjectConfigResponse,
setProjectConfigTransaction,
callbackPayload,
published
};
}
FILE:scripts/src/workflow/uploads.ts
import { createCuimpHttp } from "cuimp";
import type { CuimpInstance } from "cuimp";
import { DEFAULT_OSS_UPLOAD_TIMEOUT_MS } from "../config";
import {
assertSafeUploadFileName,
inferUploadExtension,
validateLocalImageUpload
} from "../security/upload-guard";
import type {
DesignUploadPayload,
DropType,
ElementApiResponse,
OssSignedPostData,
PreRevealUploadPayload
} from "../types";
export interface UploadedAssetRef {
sourcePath: string;
fileName: string;
objectKey: string;
publicUrl: string;
}
export interface UploadAuthContext {
authorization: string;
walletAddress: string;
}
export interface PreRevealUploadInput {
mode: "prereveal";
chainMId: number;
contractAddress: string;
dropType: DropType;
filePath: string;
}
export interface DesignUploadInput {
mode: "design";
chainMId: number;
contractAddress: string;
dropID: number;
dropName: string;
bannerFilePath?: string;
previewFilePaths: string[];
}
export type UploadInput = PreRevealUploadInput | DesignUploadInput;
export interface UploadDeps {
getOssSignSingle: (
authorization: string,
query: { chainMId: number; contractAddress: string; mediaType: "prereveal" | "design" },
walletAddress?: string
) => Promise<ElementApiResponse<OssSignedPostData>>;
postPreReveal: (
authorization: string,
body: PreRevealUploadPayload,
walletAddress?: string
) => Promise<ElementApiResponse<null>>;
uploadAsset: (input: {
filePath: string;
fileName: string;
oss: OssSignedPostData;
}) => Promise<UploadedAssetRef>;
}
export interface CuimpUploadDeps {
createClient?: () => Pick<CuimpInstance, "request">;
}
function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
return new Promise<T>((resolve, reject) => {
const timeoutHandle = setTimeout(() => {
reject(new Error(`label timed out after msms`));
}, ms);
promise.then(
(value) => {
clearTimeout(timeoutHandle);
resolve(value);
},
(error) => {
clearTimeout(timeoutHandle);
reject(error);
}
);
});
}
export function convertOssUrlToPublicUrl(url: string): string {
return url
.replace(
"https://element-master.oss-cn-hongkong.aliyuncs.com/creator-studio/",
"https://c.nfte.ai/creator-studio/"
)
.replace("https://ele-lpd.nfte.ai/", "https://c.nfte.ai/");
}
export function buildPreRevealUploadPayload(input: {
chainMId: number;
contractAddress: string;
dropType: DropType;
publicUrl: string;
}): PreRevealUploadPayload {
return {
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropType: input.dropType,
preRevealExt: {
image_url: input.publicUrl,
animation_url: ""
}
};
}
export function buildDesignUploadPayload(input: {
chainMId: number;
contractAddress: string;
dropID: number;
dropName: string;
bannerUrl?: string;
previewUrls: string[];
}): DesignUploadPayload {
return {
dropID: input.dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropName: input.dropName,
bannerURL: input.bannerUrl ?? "",
previewMediaExt: input.previewUrls.map((url) => ({
image_url: url,
animation_url: ""
})),
dropFeaturedImage: "",
description: "",
website: "",
twitter: "",
instagram: "",
discord: "",
telegram: "",
medium: "",
detailsUpdate: []
};
}
export async function uploadAssetGroupWithExistingAuthorization(input: {
auth: UploadAuthContext;
chainMId: number;
contractAddress: string;
mediaType: "prereveal" | "design";
files: Array<{
filePath: string;
fileName: string;
}>;
}, deps: Pick<UploadDeps, "getOssSignSingle" | "uploadAsset">): Promise<UploadedAssetRef[]> {
const uploads: UploadedAssetRef[] = [];
for (const file of input.files) {
const sign = await deps.getOssSignSingle(
input.auth.authorization,
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
mediaType: input.mediaType
},
input.auth.walletAddress
);
uploads.push(
await deps.uploadAsset({
filePath: file.filePath,
fileName: file.fileName,
oss: sign.data
})
);
}
return uploads;
}
export async function uploadSingleAsset(input: {
filePath: string;
fileName: string;
oss: OssSignedPostData;
}, deps: CuimpUploadDeps = {}): Promise<UploadedAssetRef> {
return uploadAssetWithCuimp(input, deps);
}
export async function uploadAssetWithCuimp(
input: {
filePath: string;
fileName: string;
oss: OssSignedPostData;
},
deps: CuimpUploadDeps = {}
): Promise<UploadedAssetRef> {
assertSafeUploadFileName(input.fileName);
const validated = await validateLocalImageUpload(input.filePath);
const objectKey = `input.oss.dir.replace(/\/$/, "")/input.fileName`;
const mimeType = validated.mimeType;
const extraCurlArgs = [
"-F",
`name=input.fileName`,
"-F",
`key=objectKey`,
"-F",
"success_action_status=200",
"-F",
`policy=input.oss.policy`
];
if (input.oss.x_oss_credential && input.oss.x_oss_date) {
extraCurlArgs.push("-F", `x-oss-signature=input.oss.signature`);
extraCurlArgs.push("-F", "x-oss-signature-version=OSS4-HMAC-SHA256");
extraCurlArgs.push("-F", `x-oss-credential=input.oss.x_oss_credential`);
extraCurlArgs.push("-F", `x-oss-date=input.oss.x_oss_date`);
if (input.oss.security_token) {
extraCurlArgs.push("-F", `x-oss-security-token=input.oss.security_token`);
}
if (input.oss.callback) {
extraCurlArgs.push("-F", `callback=input.oss.callback`);
}
} else {
extraCurlArgs.push("-F", `OSSAccessKeyId=input.oss.accessid`);
extraCurlArgs.push("-F", `signature=input.oss.signature`);
}
extraCurlArgs.push(
"-F",
`file=@validated.realPath;type=mimeType;filename=input.fileName`
);
const client =
(deps.createClient ??
(() => createCuimpHttp()))();
const response = await withTimeout(
client.request({
url: input.oss.host,
method: "POST",
headers: {
Accept: "*/*",
Referer: "https://element.market/",
Origin: "https://element.market"
},
extraCurlArgs
}),
DEFAULT_OSS_UPLOAD_TIMEOUT_MS,
`OSS upload request to input.oss.host`
);
const responseRecord = response as unknown as Record<string, unknown>;
const responseBody =
"data" in responseRecord
? responseRecord.data
: "body" in responseRecord
? responseRecord.body
: response;
if (response.status !== 200) {
console.error(
`[element-drop] external response "POST",
url: input.oss.host,
status: response.status,
body: responseBody)}`
);
throw new Error(
`OSS upload failed with status response.status: JSON.stringify(responseBody)`
);
}
const publicUrl = convertOssUrlToPublicUrl(`input.oss.host/objectKey`);
return {
sourcePath: validated.realPath,
fileName: input.fileName,
objectKey,
publicUrl
};
}
function inferExtension(filePath: string): string {
return inferUploadExtension(filePath);
}
export async function uploadWithExistingAuthorization(
auth: UploadAuthContext,
input: UploadInput,
deps: UploadDeps
) {
if (input.mode === "prereveal") {
const [asset] = await uploadAssetGroupWithExistingAuthorization(
{
auth,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
mediaType: "prereveal",
files: [
{
filePath: input.filePath,
fileName: `pre-revealinferExtension(input.filePath)`
}
]
},
deps
);
const payload = buildPreRevealUploadPayload({
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropType: input.dropType,
publicUrl: asset.publicUrl
});
const response = await deps.postPreReveal(auth.authorization, payload, auth.walletAddress);
return {
mode: "prereveal" as const,
uploads: [asset],
publicUrls: [asset.publicUrl],
payload,
response
};
}
const uploads = await uploadAssetGroupWithExistingAuthorization(
{
auth,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
mediaType: "design",
files: [
...(input.bannerFilePath
? [
{
filePath: input.bannerFilePath,
fileName: `bannerinferExtension(input.bannerFilePath)`
}
]
: []),
...input.previewFilePaths.map((filePath, index) => ({
filePath,
fileName: `preview-index + 1inferExtension(filePath)`
}))
]
},
deps
);
const bannerUpload = input.bannerFilePath ? uploads[0] : null;
const previewUploads = input.bannerFilePath ? uploads.slice(1) : uploads;
const payload = buildDesignUploadPayload({
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID: input.dropID,
dropName: input.dropName,
bannerUrl: bannerUpload?.publicUrl,
previewUrls: previewUploads.map((item) => item.publicUrl)
});
return {
mode: "design" as const,
uploads,
publicUrls: uploads.map((item) => item.publicUrl),
payload
};
}
FILE:scripts/src/workflow/design-payloads.ts
import type {
DesignUploadPayload,
ElementCollectionDetailFromEditors,
ElementCollectionEditInput,
GetDropDesignResponse
} from "../types";
import { normalizeSocialLinkSuffix, normalizeWebsiteUrl } from "./links";
export interface CollectionMetadataPatch {
description?: string;
website?: string;
twitter?: string;
instagram?: string;
discord?: string;
telegram?: string;
medium?: string;
}
export interface DesignPayloadPatch extends CollectionMetadataPatch {
name?: string;
preReveal?: string;
previewMedia?: string[];
bannerFilePath?: string;
previewFilePaths?: string[];
dropFeaturedImage?: string;
}
const EMPTY_DESIGN: GetDropDesignResponse = {
dropID: 0,
dropName: "",
bannerURL: "",
previewMedia: [],
previewMediaExt: [],
description: "",
website: "",
twitter: "",
instagram: "",
discord: "",
telegram: "",
medium: "",
dropFeaturedImage: "",
details: []
};
export function hasCollectionMetadataOverride(input: CollectionMetadataPatch): boolean {
return Boolean(
input.description !== undefined ||
input.website !== undefined ||
input.twitter !== undefined ||
input.instagram !== undefined ||
input.discord !== undefined ||
input.telegram !== undefined ||
input.medium !== undefined
);
}
export function hasDesignOverride(input: DesignPayloadPatch): boolean {
return Boolean(
input.preReveal !== undefined ||
input.previewMedia !== undefined ||
input.bannerFilePath ||
(input.previewFilePaths && input.previewFilePaths.length > 0) ||
input.name !== undefined ||
input.description !== undefined ||
input.dropFeaturedImage !== undefined
);
}
export function buildCollectionEditPayload(input: {
current: ElementCollectionDetailFromEditors;
patch: CollectionMetadataPatch;
token: string;
imageFilePath?: string;
}): ElementCollectionEditInput {
return {
collectionId: input.current.id,
token: input.token,
imageFilePath: input.imageFilePath,
image: input.imageFilePath ? null : undefined,
description: input.patch.description ?? input.current.description ?? undefined,
externalUrl: normalizeWebsiteUrl(input.patch.website ?? input.current.externalUrl) || undefined,
twitterUrl: normalizeSocialLinkSuffix("twitter", input.patch.twitter ?? input.current.twitterUrl) || undefined,
instagramUrl:
normalizeSocialLinkSuffix("instagram", input.patch.instagram ?? input.current.instagramUrl) || undefined,
discordUrl: normalizeSocialLinkSuffix("discord", input.patch.discord ?? input.current.discordUrl) || undefined,
telegramUrl:
normalizeSocialLinkSuffix("telegram", input.patch.telegram ?? input.current.telegramUrl) || undefined,
mediumUrl: normalizeSocialLinkSuffix("medium", input.patch.medium ?? input.current.mediumUrl) || undefined,
categories: input.current.categories.map((item) => item.id),
paymentTokens: input.current.paymentTokens.map((item) => item.id)
};
}
export function buildMergedDesignPayload(input: {
current: GetDropDesignResponse | null;
patch: DesignPayloadPatch;
chainMId: number;
contractAddress: string;
dropID: number;
uploadedBannerUrl?: string | null;
uploadedPreviewUrls?: string[];
}): DesignUploadPayload {
const current = input.current ?? EMPTY_DESIGN;
return {
dropID: input.dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropName: input.patch.name ?? current.dropName,
bannerURL: input.uploadedBannerUrl ?? current.bannerURL ?? "",
previewMediaExt: (() => {
if (input.uploadedPreviewUrls && input.uploadedPreviewUrls.length > 0) {
return input.uploadedPreviewUrls.map((url) => ({
image_url: url,
animation_url: ""
}));
}
return current.previewMediaExt.map((item) => ({
image_url: item.image_url ?? "",
animation_url: item.animation_url ?? ""
}));
})(),
dropFeaturedImage: input.patch.dropFeaturedImage ?? current.dropFeaturedImage ?? "",
description: input.patch.description ?? current.description ?? "",
website: normalizeWebsiteUrl(input.patch.website ?? current.website),
twitter: normalizeSocialLinkSuffix("twitter", input.patch.twitter ?? current.twitter),
instagram: normalizeSocialLinkSuffix("instagram", input.patch.instagram ?? current.instagram),
discord: normalizeSocialLinkSuffix("discord", input.patch.discord ?? current.discord),
telegram: normalizeSocialLinkSuffix("telegram", input.patch.telegram ?? current.telegram),
medium: normalizeSocialLinkSuffix("medium", input.patch.medium ?? current.medium),
detailsUpdate: current.details ?? []
};
}
export function buildDisplayDesignAfterUpdate(input: {
current: GetDropDesignResponse | null;
designPayload: DesignUploadPayload | null;
collectionEditPayload: ElementCollectionEditInput | null;
}) {
const hasAnyUpdate = Boolean(input.current || input.designPayload || input.collectionEditPayload);
if (!hasAnyUpdate) {
return null;
}
const current = input.current ?? EMPTY_DESIGN;
const design = input.designPayload;
const collection = input.collectionEditPayload;
return {
bannerURL: design?.bannerURL ?? current.bannerURL ?? "",
previewMediaExt: design?.previewMediaExt ?? current.previewMediaExt ?? [],
description: design?.description ?? current.description ?? "",
website: collection?.externalUrl ?? design?.website ?? current.website ?? "",
twitter: collection?.twitterUrl ?? design?.twitter ?? current.twitter ?? "",
instagram: collection?.instagramUrl ?? design?.instagram ?? current.instagram ?? "",
discord: collection?.discordUrl ?? design?.discord ?? current.discord ?? "",
telegram: collection?.telegramUrl ?? design?.telegram ?? current.telegram ?? "",
medium: collection?.mediumUrl ?? design?.medium ?? current.medium ?? "",
dropFeaturedImage: design?.dropFeaturedImage ?? current.dropFeaturedImage ?? ""
};
}
FILE:scripts/src/workflow/create-drop.ts
import { normalizeCreateDropInput } from "../schema";
import { resolveMintingTypeFromPaymentToken } from "../network/chains";
import { HttpRequestError } from "../api/http";
import { redactKnownSecrets } from "../env";
import { buildMergedDesignPayload } from "./design-payloads";
import { createTokenFlow } from "./create-token";
import { postCreateCollectionFlow } from "./post-create-collection";
import { uploadWithExistingAuthorization } from "./uploads";
import type {
CreateDropInput,
ElementApiResponse,
EncodedTransaction,
GetDropSettingsResponse,
OssSignedPostData,
ExecutedTransactionResult,
DesignUploadPayload,
PreRevealUploadPayload,
ElementCollectionDetailFromEditors,
ElementChainCollectionSummary,
ElementCollectionSummary,
ElementCollectionEditInput,
DropInput,
PostDropSettingsRequest,
ChainListPaymentToken
} from "../types";
export type WorkflowLogger = (message: string, meta?: Record<string, unknown>) => void;
export interface CreateDropFlowInput extends CreateDropInput {
chainName?: string;
paymentTokens?: ChainListPaymentToken[];
bannerFilePath?: string;
previewFilePaths?: string[];
pollIntervalMs?: number;
timeoutMs?: number;
preRevealIPFSPollIntervalMs?: number;
preRevealIPFSTimeoutMs?: number;
}
export function createWorkflowLogger(): WorkflowLogger {
return (message, meta = {}) => {
if (!message.endsWith(":failed")) {
return;
}
const timestamp = new Date().toISOString();
console.error(`[element-drop] timestamp message JSON.stringify(meta)`);
};
}
export function buildDropUrls(slug: string) {
return {
dropUrl: `https://element.market/drop/slug`,
collectionUrl: `https://element.market/collections/slug`,
editUrl: `https://element.market/collections/slug/edit/drop`
};
}
export function buildCreatedDropSummary(result: {
chainName?: string;
symbol?: string;
contractAddress: string;
dropID: number;
slug: string;
urls: {
dropUrl: string;
collectionUrl: string;
editUrl: string;
};
createToken: {
transaction: {
hash: string;
};
};
}) {
return {
chainName: result.chainName ?? null,
symbol: result.symbol ?? null,
contractAddress: result.contractAddress,
dropID: result.dropID,
slug: result.slug,
createTransactionHash: result.createToken.transaction.hash,
dropUrl: result.urls.dropUrl,
collectionUrl: result.urls.collectionUrl,
editUrl: result.urls.editUrl,
nextRecommendedAction:
result.chainName && result.slug
? {
action: "publish-drop",
description:
"The drop is configured but not live yet. Preview publish, then publish after explicit confirmation.",
payload: {
chainName: result.chainName,
slug: result.slug
}
}
: null
};
}
export async function runStage<T>(
logger: WorkflowLogger,
stage: string,
fn: () => Promise<T>
): Promise<T> {
try {
return await fn();
} catch (error) {
const message = redactKnownSecrets(error instanceof Error ? error.message : String(error));
const httpMeta =
error instanceof HttpRequestError
? {
method: error.method,
url: error.url,
status: error.status,
attempts: error.attempts,
maxAttempts: error.maxAttempts,
durationMs: error.durationMs,
timedOut: error.timedOut,
retriable: error.retriable
}
: undefined;
logger(`stage:failed`, {
error: message,
...(httpMeta ? { http: httpMeta } : {})
});
const suffix = httpMeta
? ` [httpMeta.method httpMeta.url; attempts=httpMeta.attempts/httpMeta.maxAttempts; status=httpMeta.status ?? "network"; timeout=httpMeta.timedOut; durationMs=httpMeta.durationMs]`
: "";
throw new Error(`stage failed: messagesuffix`);
}
}
export interface CreateDropFlowDeps {
createTokenFlow: typeof createTokenFlow;
postCreateCollectionFlow: typeof postCreateCollectionFlow;
uploadWithExistingAuthorization: typeof uploadWithExistingAuthorization;
getDropSettings: (
query: { chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropSettingsResponse>>;
postDropSettings: (
authorization: string,
body: PostDropSettingsRequest,
walletAddress: string
) => Promise<ElementApiResponse<null>>;
getOssSignSingle: (
authorization: string,
query: { chainMId: number; contractAddress: string; mediaType: "prereveal" | "design" },
walletAddress?: string
) => Promise<ElementApiResponse<OssSignedPostData>>;
postPreReveal: (
authorization: string,
body: PreRevealUploadPayload,
walletAddress?: string
) => Promise<ElementApiResponse<null>>;
postDesign: (
authorization: string,
body: DesignUploadPayload,
walletAddress?: string
) => Promise<ElementApiResponse<null>>;
uploadAsset: (input: {
filePath: string;
fileName: string;
oss: OssSignedPostData;
}) => Promise<{
sourcePath: string;
fileName: string;
objectKey: string;
publicUrl: string;
}>;
createAuthorization: (chainMId: number) => Promise<{
authorization: string;
walletAddress: string;
nonce: string;
loginMessage: string;
identity: {
address: string;
blockChain: {
chain: string;
chainId: string;
};
};
}>;
deriveAddress: (input: { privateKey: string }) => Promise<string>;
resolveRpcUrl: (chainMId: number) => Promise<string>;
createAuthorizationForToken: (input: {
privateKey: string;
walletAddress?: string;
chainMId: number;
}) => Promise<{
authorization: string;
nonce: string;
message: string;
identity: {
address: string;
blockChain: {
chain: string;
chainId: string;
};
};
}>;
postCreateToken: (
authorization: string,
body: { chainMId: number; name: string; symbol: string },
walletAddress?: string
) => Promise<ElementApiResponse<EncodedTransaction>>;
sendTransaction: (input: {
rpcUrl: string;
transaction: EncodedTransaction;
waitConfirmations?: number;
}) => Promise<ExecutedTransactionResult>;
getCollectionContract: (input: {
address: string;
blockChain: {
chain: string;
chainId: string;
};
}) => Promise<ElementChainCollectionSummary | null>;
getMutateToken: (authorization?: string) => Promise<string>;
getCollectionDetailFromEditors: (
slug: string,
authorization?: string
) => Promise<ElementCollectionDetailFromEditors>;
collectionEdit: (input: ElementCollectionEditInput, authorization?: string) => Promise<ElementCollectionSummary>;
}
export function buildInitialSettingsPayload(input: {
normalized: Pick<DropInput, "chainMId" | "dropType" | "maxSupply" | "dropBeginTime" | "stages" | "paymentToken">;
contractAddress: string;
availablePaymentTokens?: ChainListPaymentToken[];
}): PostDropSettingsRequest {
return {
dropID: 0,
chainMId: input.normalized.chainMId,
contractAddress: input.contractAddress,
dropType: input.normalized.dropType,
maxSupply: input.normalized.maxSupply,
fee: 0,
feeRecipient: "",
mintingType: resolveMintingTypeFromPaymentToken({
paymentToken: input.normalized.paymentToken,
availablePaymentTokens: input.availablePaymentTokens
}),
dropBeginTime: input.normalized.dropBeginTime,
stagesUpdate: input.normalized.stages.map((stage) => ({
stageID: stage.stageID,
stageName: stage.stageName,
price: stage.price,
interval: stage.interval,
duration: stage.duration,
maxMintedPerWallet: stage.maxMintedPerWallet,
maxSupplyAtThisStage: stage.maxSupplyAtThisStage,
stageMode: stage.stageMode,
allowListsNew: []
}))
};
}
export async function createDropFlow(input: CreateDropFlowInput, deps: CreateDropFlowDeps) {
const logger = createWorkflowLogger();
const normalized = normalizeCreateDropInput(input);
const createToken = await runStage(logger, "createToken", () =>
deps.createTokenFlow(normalized, {
deriveAddress: deps.deriveAddress,
resolveRpcUrl: deps.resolveRpcUrl,
createAuthorization: deps.createAuthorizationForToken,
postCreateToken: deps.postCreateToken,
sendTransaction: deps.sendTransaction,
logger
})
);
const contractAddress = createToken.transaction.contractAddress;
if (!contractAddress) {
throw new Error("contractAddress missing from createToken transaction receipt");
}
const postCreateCollection = await runStage(logger, "postCreateCollection", () =>
deps.postCreateCollectionFlow(
{
chainMId: normalized.chainMId,
contractAddress,
authorization: createToken.preflight.authorization,
imageFilePath: normalized.preReveal,
collectionMetadata: {
description: normalized.description,
website: input.website,
twitter: input.twitter,
instagram: input.instagram,
discord: input.discord,
telegram: input.telegram,
medium: input.medium
},
pollIntervalMs: input.pollIntervalMs,
timeoutMs: input.timeoutMs
},
{
getCollectionContract: deps.getCollectionContract,
getMutateToken: deps.getMutateToken,
getCollectionDetailFromEditors: deps.getCollectionDetailFromEditors,
collectionEdit: deps.collectionEdit,
logger
}
)
);
const auth = {
authorization: createToken.preflight.authorization,
walletAddress: createToken.preflight.walletAddress
};
const initialSettingsPayload = buildInitialSettingsPayload({
normalized,
contractAddress,
availablePaymentTokens: input.paymentTokens
});
const initialSettings = await runStage(logger, "postInitialSettings", () =>
deps.postDropSettings(auth.authorization, initialSettingsPayload, auth.walletAddress)
);
const settingsAfterCreate = await runStage(logger, "getSettingsAfterCreate", () =>
deps.getDropSettings(
{
chainMId: normalized.chainMId,
contractAddress
},
auth.walletAddress
)
);
const dropID = settingsAfterCreate.data.dropID;
if (!(dropID > 0)) {
throw new Error(`getSettingsAfterCreate returned invalid dropID for contractAddress: dropID`);
}
const preRevealUpload = await runStage(logger, "uploadPreReveal", () =>
deps.uploadWithExistingAuthorization(
auth,
{
mode: "prereveal",
chainMId: normalized.chainMId,
contractAddress,
dropType: normalized.dropType,
filePath: normalized.preReveal
},
{
getOssSignSingle: deps.getOssSignSingle,
postPreReveal: deps.postPreReveal,
uploadAsset: deps.uploadAsset
}
)
);
const designBannerFilePath = input.bannerFilePath ?? normalized.preReveal;
const designPreviewFilePaths = input.previewMedia?.length
? input.previewMedia
: input.previewFilePaths?.length
? input.previewFilePaths
: [normalized.preReveal];
const designUpload = await runStage(logger, "uploadDesign", () =>
deps.uploadWithExistingAuthorization(
auth,
{
mode: "design",
chainMId: normalized.chainMId,
contractAddress,
dropID,
dropName: normalized.name,
bannerFilePath: designBannerFilePath,
previewFilePaths: designPreviewFilePaths
},
{
getOssSignSingle: deps.getOssSignSingle,
postPreReveal: deps.postPreReveal,
uploadAsset: deps.uploadAsset
}
)
);
if (designUpload.mode !== "design") {
throw new Error("uploadDesign returned a non-design payload");
}
const designPayload = buildMergedDesignPayload({
current: {
dropID,
dropName: designUpload.payload.dropName,
bannerURL: designUpload.payload.bannerURL,
previewMedia: [],
previewMediaExt: designUpload.payload.previewMediaExt,
description: "",
website: "",
twitter: "",
instagram: "",
discord: "",
telegram: "",
medium: "",
dropFeaturedImage: "",
details: []
},
patch: {
name: normalized.name,
description: normalized.description,
website: input.website,
twitter: input.twitter,
instagram: input.instagram,
discord: input.discord,
telegram: input.telegram,
medium: input.medium,
dropFeaturedImage: input.dropFeaturedImage
},
chainMId: normalized.chainMId,
contractAddress,
dropID
});
const designResponse = await runStage(logger, "postDesign", () =>
deps.postDesign(auth.authorization, designPayload, auth.walletAddress)
);
const designBannerUrl = designPayload.bannerURL;
const designPreviewCount = designPayload.previewMediaExt.length;
const slug = postCreateCollection.collectionContract.collection.slug;
const urls = buildDropUrls(slug);
return {
normalized,
contractAddress,
createToken,
postCreateCollection,
preRevealUpload,
initialSettingsPayload,
initialSettings,
settingsAfterCreate,
dropID,
slug,
urls,
designUpload: {
...designUpload,
payload: designPayload
},
designResponse,
designBannerUrl,
summary: buildCreatedDropSummary({
chainName: input.chainName,
symbol: normalized.symbol,
contractAddress,
dropID,
slug,
urls,
createToken
})
};
}
FILE:scripts/src/workflow/preview-drop.ts
import { buildDropUrls, createWorkflowLogger, runStage } from "./create-drop";
import type {
ElementApiResponse,
GetDropDesignResponse,
GetDropSettingsResponse,
GetTempURLResponse
} from "../types";
export interface PreviewDropFlowInput {
authorization: string;
walletAddress: string;
chainMId: number;
contractAddress: string;
slug?: string;
page?: number;
pageSize?: number;
}
export interface PreviewDropFlowDeps {
getDropSettings: (
query: { chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropSettingsResponse>>;
getDropDesign: (
query: { dropID: number; chainMId: number; contractAddress: string },
walletAddress: string
) => Promise<ElementApiResponse<GetDropDesignResponse>>;
getTempURL: (
authorization: string,
query: { chainMId: number; contractAddress: string; dropID: number; page: number; pageSize: number },
walletAddress: string
) => Promise<ElementApiResponse<GetTempURLResponse>>;
}
function summarizePublishState(input: { published?: unknown; isPaused?: unknown }) {
if (input.published !== 1) {
return {
status: "draft",
label: "draft"
};
}
if (input.isPaused === true) {
return {
status: "paused",
label: "paused"
};
}
return {
status: "live",
label: "live"
};
}
export async function previewDropFlow(input: PreviewDropFlowInput, deps: PreviewDropFlowDeps) {
const logger = createWorkflowLogger();
const settings = await runStage(logger, "preview:getSettings", () =>
deps.getDropSettings(
{
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
)
);
const dropID = settings.data.dropID;
const design =
dropID > 0
? await runStage(logger, "preview:getDesign", () =>
deps.getDropDesign(
{
dropID,
chainMId: input.chainMId,
contractAddress: input.contractAddress
},
input.walletAddress
)
)
: null;
const tempURL =
dropID > 0
? await runStage(logger, "preview:getTempURL", () =>
deps.getTempURL(
input.authorization,
{
chainMId: input.chainMId,
contractAddress: input.contractAddress,
dropID,
page: input.page ?? 1,
pageSize: input.pageSize ?? 20
},
input.walletAddress
)
)
: null;
return {
chainMId: input.chainMId,
contractAddress: input.contractAddress,
slug: input.slug ?? null,
urls: input.slug ? buildDropUrls(input.slug) : null,
settings,
design,
tempURL,
summary: {
slug: input.slug ?? null,
...(input.slug ? buildDropUrls(input.slug) : { dropUrl: null, collectionUrl: null, editUrl: null }),
publishState: summarizePublishState({
published: settings.data.published,
isPaused: settings.data.isPaused
}),
batch: settings.data.batch,
stageCount: settings.data.stages?.length ?? 0,
hasDesign: Boolean(design?.data),
hasPreRevealMedia: Boolean(
tempURL?.data?.preReveal?.image_url?.trim() ?? tempURL?.data?.preReveal?.imageURL?.trim()
)
}
};
}
FILE:scripts/src/workflow/links.ts
const SOCIAL_LINK_PREFIXES = {
twitter: ["https://x.com/", "https://twitter.com/"],
instagram: ["https://www.instagram.com/", "https://instagram.com/"],
discord: ["https://discord.gg/"],
telegram: ["https://t.me/"],
medium: ["https://www.medium.com/@", "https://medium.com/@", "https://www.medium.com/", "https://medium.com/"]
} as const;
export type SocialLinkField = keyof typeof SOCIAL_LINK_PREFIXES;
const SOCIAL_LINK_DISPLAY_PREFIX = {
twitter: "https://x.com/",
instagram: "https://www.instagram.com/",
discord: "https://discord.gg/",
telegram: "https://t.me/",
medium: "https://www.medium.com/@"
} as const;
function stripKnownPrefix(value: string, prefixes: readonly string[]) {
for (const prefix of prefixes) {
if (value.startsWith(prefix)) {
return value.slice(prefix.length);
}
}
return value;
}
function trimSlashes(value: string) {
return value.replace(/^\/+/, "").replace(/\/+$/, "");
}
export function normalizeWebsiteUrl(value: string | null | undefined) {
return typeof value === "string" ? value.trim() : "";
}
export function normalizeSocialLinkSuffix(field: SocialLinkField, value: string | null | undefined) {
if (typeof value !== "string") {
return "";
}
let normalized = value.trim();
if (!normalized) {
return "";
}
normalized = stripKnownPrefix(normalized, SOCIAL_LINK_PREFIXES[field]);
if (field === "medium" && normalized.startsWith("@")) {
normalized = normalized.slice(1);
}
return trimSlashes(normalized);
}
export function formatSocialLinkForDisplay(field: SocialLinkField, value: string | null | undefined) {
const suffix = normalizeSocialLinkSuffix(field, value);
if (!suffix) {
return "";
}
return `SOCIAL_LINK_DISPLAY_PREFIX[field]suffix`;
}
FILE:scripts/src/workflow/verify-ref-graphql.ts
import { buildElementAuthorization, deriveWalletAddress } from "../auth/jwt";
import { getRequiredWalletPrivateKey } from "../env";
import { createElementGraphqlClient } from "../api/graphql";
export async function verifyRefGraphqlExamples() {
const privateKey = getRequiredWalletPrivateKey();
const walletAddress = (await deriveWalletAddress({ privateKey })).toLowerCase();
const graphql = createElementGraphqlClient();
const authorization = (
await buildElementAuthorization(
{
getLoginNonce: graphql.getLoginNonce,
loginAuth: graphql.loginAuth
},
{
privateKey,
walletAddress,
chainMId: 1201
}
)
).authorization;
const results: Record<string, unknown> = {};
results.getNonce = await graphql.getLoginNonce({
address: "0x00000007699893e07f12d7d35ac7e4534c31613e",
blockChain: {
chain: "eth",
chainId: "0x1"
}
});
results.collectionContract = await graphql.getCollectionContract({
address: "0x7122ad8c3f90fd23cb89d3ffa5ce7feac8d64c6a",
blockChain: {
chain: "base",
chainId: "0x2105"
}
});
results.getMutateToken = await graphql.getMutateToken(authorization);
results.collectionDetailFromEditors = await graphql.getCollectionDetailFromEditors(
"1122-5",
authorization
);
try {
results.collectionEdit = await graphql.collectionEdit(
{
collectionId: "18829680",
token: String(results.getMutateToken),
image: null
},
authorization
);
} catch (error) {
results.collectionEdit = {
ok: false,
error: error instanceof Error ? error.message : String(error)
};
}
return {
authorization,
walletAddress,
results
};
}
FILE:scripts/src/workflow/wait-collection-contract.ts
import { getElementBlockChainByChainMId } from "../auth/jwt";
import type { ElementChainCollectionSummary } from "../types";
export interface WaitForCollectionContractInput {
chainMId: number;
contractAddress: string;
pollIntervalMs?: number;
timeoutMs?: number;
}
export interface WaitForCollectionContractDeps {
getCollectionContract: (input: {
address: string;
blockChain: {
chain: string;
chainId: string;
};
}) => Promise<ElementChainCollectionSummary | null>;
sleep?: (ms: number) => Promise<void>;
now?: () => number;
logger?: (message: string, meta?: Record<string, unknown>) => void;
}
async function defaultSleep(ms: number): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, ms));
}
export async function waitForCollectionContract(
input: WaitForCollectionContractInput,
deps: WaitForCollectionContractDeps
) {
const pollIntervalMs = input.pollIntervalMs ?? 5_000;
const timeoutMs = input.timeoutMs ?? 10 * 60 * 1000;
const sleep = deps.sleep ?? defaultSleep;
const now = deps.now ?? Date.now;
const blockChain = getElementBlockChainByChainMId(input.chainMId);
const startedAt = now();
let attempts = 0;
while (true) {
attempts += 1;
deps.logger?.("collectionContract:poll", {
attempt: attempts,
contractAddress: input.contractAddress,
elapsedMs: now() - startedAt
});
const collection = await deps.getCollectionContract({
address: input.contractAddress,
blockChain
});
if (collection) {
deps.logger?.("collectionContract:resolved", {
attempt: attempts,
contractAddress: input.contractAddress,
slug: collection.slug,
collectionId: collection.id,
elapsedMs: now() - startedAt
});
return {
contractAddress: input.contractAddress,
blockChain,
attempts,
elapsedMs: now() - startedAt,
collection
};
}
if (now() - startedAt >= timeoutMs) {
throw new Error(
`CollectionContract timed out after attempts attempts (timeoutMsms) for input.contractAddress`
);
}
await sleep(pollIntervalMs);
}
}
FILE:scripts/src/api/http.ts
import { DEFAULT_NETWORK_TIMEOUT_MS } from "../config";
function summarizeForLog(value: unknown): unknown {
if (typeof value === "string") {
return value.length > 4000 ? `value.slice(0, 4000)...<truncated>` : value;
}
if (Array.isArray(value)) {
return value.map((item) => summarizeForLog(item));
}
if (value && typeof value === "object") {
return Object.fromEntries(
Object.entries(value).map(([key, nested]) => [key, summarizeForLog(nested)])
);
}
return value;
}
const DEFAULT_HTTP_TIMEOUT_MS = DEFAULT_NETWORK_TIMEOUT_MS;
const DEFAULT_HTTP_MAX_ATTEMPTS = 3;
const DEFAULT_HTTP_RETRY_DELAY_MS = 1_500;
export class HttpRequestError extends Error {
readonly method: string;
readonly url: string;
readonly status?: number;
readonly attempts: number;
readonly maxAttempts: number;
readonly durationMs: number;
readonly timedOut: boolean;
readonly retriable: boolean;
readonly responseBody?: unknown;
constructor(input: {
method: string;
url: string;
status?: number;
attempts: number;
maxAttempts: number;
durationMs: number;
timedOut: boolean;
retriable: boolean;
responseBody?: unknown;
message: string;
cause?: unknown;
}) {
super(input.message, input.cause ? { cause: input.cause } : undefined);
this.name = "HttpRequestError";
this.method = input.method;
this.url = input.url;
this.status = input.status;
this.attempts = input.attempts;
this.maxAttempts = input.maxAttempts;
this.durationMs = input.durationMs;
this.timedOut = input.timedOut;
this.retriable = input.retriable;
this.responseBody = input.responseBody;
}
}
function summarizeForMessage(value: unknown): string {
if (typeof value === "string") {
return value.length > 500 ? `value.slice(0, 500)...<truncated>` : value;
}
try {
return JSON.stringify(summarizeForLog(value));
} catch {
return String(value);
}
}
function logExternalFailure(input: {
method: string;
url: string;
status?: number;
body?: unknown;
attempt?: number;
maxAttempts?: number;
durationMs?: number;
timedOut?: boolean;
retriable?: boolean;
error?: string;
}) {
console.error(
`[element-drop] external response input.method,
url: input.url,
status: input.status,
attempt: input.attempt,
maxAttempts: input.maxAttempts,
durationMs: input.durationMs,
timedOut: input.timedOut,
retriable: input.retriable,
error: input.error,
body: summarizeForLog(input.body))}`
);
}
function isRetryableStatus(status: number): boolean {
return status === 408 || status === 425 || status === 429 || status >= 500;
}
function shouldRetry(input: { status?: number; timedOut: boolean; error?: unknown }): boolean {
if (input.timedOut) {
return true;
}
if (typeof input.status === "number") {
return isRetryableStatus(input.status);
}
if (!input.error) {
return false;
}
if (input.error instanceof TypeError) {
return true;
}
if (input.error instanceof Error && input.error.name === "AbortError") {
return true;
}
return false;
}
async function sleep(ms: number): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, ms));
}
async function parseResponseBody(response: Response): Promise<unknown> {
let body: unknown;
try {
body = await response.json();
} catch {
body = await response.text();
}
return body;
}
async function requestJson<T>(
url: string,
init: {
method: "GET" | "POST";
headers?: Record<string, string>;
body?: string;
timeoutMs?: number;
maxAttempts?: number;
retryDelayMs?: number;
}
): Promise<T> {
const timeoutMs = init.timeoutMs ?? DEFAULT_HTTP_TIMEOUT_MS;
const maxAttempts = Math.max(1, init.maxAttempts ?? DEFAULT_HTTP_MAX_ATTEMPTS);
const retryDelayMs = init.retryDelayMs ?? DEFAULT_HTTP_RETRY_DELAY_MS;
const startedAt = Date.now();
let attempt = 0;
let lastFailure: HttpRequestError | undefined;
while (attempt < maxAttempts) {
attempt += 1;
const controller = new AbortController();
const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
const attemptStartedAt = Date.now();
try {
const response = await fetch(url, {
method: init.method,
headers: init.headers,
body: init.body,
signal: controller.signal
});
clearTimeout(timeoutHandle);
const body = await parseResponseBody(response);
if (response.ok) {
return body as T;
}
const retriable = shouldRetry({ status: response.status, timedOut: false });
const error = new HttpRequestError({
method: init.method,
url,
status: response.status,
attempts: attempt,
maxAttempts,
durationMs: Date.now() - startedAt,
timedOut: false,
retriable,
responseBody: body,
message: `HTTP response.status for url: summarizeForMessage(body)`
});
lastFailure = error;
logExternalFailure({
method: init.method,
url,
status: response.status,
body,
attempt,
maxAttempts,
durationMs: Date.now() - attemptStartedAt,
timedOut: false,
retriable
});
if (!retriable || attempt >= maxAttempts) {
throw error;
}
} catch (error) {
clearTimeout(timeoutHandle);
const timedOut = error instanceof Error && error.name === "AbortError";
const retriable = shouldRetry({ timedOut, error });
const wrapped =
error instanceof HttpRequestError
? error
: new HttpRequestError({
method: init.method,
url,
attempts: attempt,
maxAttempts,
durationMs: Date.now() - startedAt,
timedOut,
retriable,
message: timedOut
? `HTTP timeout after timeoutMsms for url`
: `HTTP request failed for url: String(error)`,
cause: error
});
lastFailure = wrapped;
if (error instanceof HttpRequestError) {
throw error;
}
logExternalFailure({
method: init.method,
url,
attempt,
maxAttempts,
durationMs: Date.now() - attemptStartedAt,
timedOut,
retriable,
error: error instanceof Error ? error.message : String(error)
});
if (!retriable || attempt >= maxAttempts) {
throw wrapped;
}
}
await sleep(retryDelayMs * attempt);
}
if (lastFailure) {
throw lastFailure;
}
throw new HttpRequestError({
method: init.method,
url,
attempts: maxAttempts,
maxAttempts,
durationMs: Date.now() - startedAt,
timedOut: false,
retriable: false,
message: `HTTP request failed for url`
});
}
export async function getJson<T>(
url: string,
init?: {
headers?: Record<string, string>;
timeoutMs?: number;
maxAttempts?: number;
retryDelayMs?: number;
}
): Promise<T> {
return requestJson<T>(url, {
method: "GET",
headers: init?.headers,
timeoutMs: init?.timeoutMs,
maxAttempts: init?.maxAttempts,
retryDelayMs: init?.retryDelayMs
});
}
export async function postJson<T>(
url: string,
init: {
body: unknown;
headers?: Record<string, string>;
timeoutMs?: number;
maxAttempts?: number;
retryDelayMs?: number;
}
): Promise<T> {
return requestJson<T>(url, {
method: "POST",
headers: {
"content-type": "application/json",
...(init.headers ?? {})
},
body: JSON.stringify(init.body),
timeoutMs: init.timeoutMs,
maxAttempts: init.maxAttempts,
retryDelayMs: init.retryDelayMs
});
}
FILE:scripts/src/api/element.ts
import { DEFAULT_DROP_API_BASE_URL } from "../config";
import { getJson, postJson } from "./http";
import type {
CallbackUpdateProjectConfigRequest,
CreateTokenRequest,
GetDropDesignQuery,
GetDropDesignResponse,
GetPreRevealIPFSQuery,
GetPreRevealIPFSResponse,
GetDropSettingsQuery,
GetDropSettingsResponse,
DesignUploadPayload,
ElementApiResponse,
EncodedTransaction,
GetChainsWithGasResponse,
GetTempURLQuery,
GetTempURLResponse,
OssSignSingleRequest,
OssSignedPostData,
PostDropSettingsRequest,
PreRevealUploadPayload,
SetProjectConfigRequest
} from "../types";
export function createElementApiClient(baseUrl = DEFAULT_DROP_API_BASE_URL) {
function withAuthHeaders(authorization: string, walletAddress?: string) {
return {
Authorization: authorization,
...(walletAddress ? { "x-viewer-addr": walletAddress } : {})
};
}
function withOwnerHeaders(walletAddress?: string) {
return walletAddress ? { "x-viewer-addr": walletAddress } : undefined;
}
return {
async getChainsWithGas(): Promise<ElementApiResponse<GetChainsWithGasResponse>> {
return getJson<ElementApiResponse<GetChainsWithGasResponse>>(`baseUrl/chain/listWithGas`);
},
async getDropSettings(
query: GetDropSettingsQuery,
walletAddress: string
): Promise<ElementApiResponse<GetDropSettingsResponse>> {
const url = new URL(`baseUrl/edit/settings`);
url.searchParams.set("chainMId", String(query.chainMId));
url.searchParams.set("contractAddress", query.contractAddress);
return getJson<ElementApiResponse<GetDropSettingsResponse>>(url.toString(), {
headers: withOwnerHeaders(walletAddress)
});
},
async postDropSettings(
authorization: string,
body: PostDropSettingsRequest,
walletAddress: string
): Promise<ElementApiResponse<null>> {
return postJson<ElementApiResponse<null>>(`baseUrl/edit/settings`, {
body,
headers: withAuthHeaders(authorization, walletAddress)
});
},
async getDropDesign(
query: GetDropDesignQuery,
walletAddress: string
): Promise<ElementApiResponse<GetDropDesignResponse>> {
const url = new URL(`baseUrl/edit/design`);
url.searchParams.set("dropID", String(query.dropID));
url.searchParams.set("chainMId", String(query.chainMId));
url.searchParams.set("contractAddress", query.contractAddress);
return getJson<ElementApiResponse<GetDropDesignResponse>>(url.toString(), {
headers: withOwnerHeaders(walletAddress)
});
},
async postCreateToken(
authorization: string,
body: CreateTokenRequest,
walletAddress?: string
): Promise<ElementApiResponse<EncodedTransaction>> {
return postJson<ElementApiResponse<EncodedTransaction>>(`baseUrl/encode/createToken`, {
body,
headers: withAuthHeaders(authorization, walletAddress)
});
},
async getOssSignSingle(
authorization: string,
query: OssSignSingleRequest,
walletAddress?: string
): Promise<ElementApiResponse<OssSignedPostData>> {
const url = new URL(`baseUrl/oss/signSingle`);
url.searchParams.set("chainMId", String(query.chainMId));
url.searchParams.set("contractAddress", query.contractAddress);
url.searchParams.set("mediaType", query.mediaType);
return getJson<ElementApiResponse<OssSignedPostData>>(url.toString(), {
headers: withAuthHeaders(authorization, walletAddress)
});
},
async postPreReveal(
authorization: string,
body: PreRevealUploadPayload,
walletAddress?: string
): Promise<ElementApiResponse<null>> {
return postJson<ElementApiResponse<null>>(`baseUrl/edit/upload/preReveal`, {
body,
headers: withAuthHeaders(authorization, walletAddress)
});
},
async postDesign(
authorization: string,
body: DesignUploadPayload,
walletAddress?: string
): Promise<ElementApiResponse<null>> {
return postJson<ElementApiResponse<null>>(`baseUrl/edit/design`, {
body,
headers: withAuthHeaders(authorization, walletAddress)
});
},
async getPreRevealIPFS(
query: GetPreRevealIPFSQuery,
walletAddress: string
): Promise<ElementApiResponse<GetPreRevealIPFSResponse>> {
const url = new URL(`baseUrl/edit/upload/preRevealIPFS`);
url.searchParams.set("chainMId", String(query.chainMId));
url.searchParams.set("contractAddress", query.contractAddress);
url.searchParams.set("dropID", String(query.dropID));
return getJson<ElementApiResponse<GetPreRevealIPFSResponse>>(url.toString(), {
headers: withOwnerHeaders(walletAddress)
});
},
async getTempURL(
authorization: string,
query: GetTempURLQuery,
walletAddress: string
): Promise<ElementApiResponse<GetTempURLResponse>> {
const url = new URL(`baseUrl/edit/upload/tempURL`);
url.searchParams.set("chainMId", String(query.chainMId));
url.searchParams.set("contractAddress", query.contractAddress);
url.searchParams.set("dropID", String(query.dropID));
url.searchParams.set("page", String(query.page));
url.searchParams.set("pageSize", String(query.pageSize));
return getJson<ElementApiResponse<GetTempURLResponse>>(url.toString(), {
headers: withAuthHeaders(authorization, walletAddress)
});
},
async postSetProjectConfig(
authorization: string,
body: SetProjectConfigRequest,
walletAddress: string
): Promise<ElementApiResponse<EncodedTransaction>> {
return postJson<ElementApiResponse<EncodedTransaction>>(`baseUrl/encode/setProjectConfig`, {
body,
headers: withAuthHeaders(authorization, walletAddress)
});
},
async postCallbackUpdateProjectConfig(
body: CallbackUpdateProjectConfigRequest
): Promise<ElementApiResponse<null>> {
return postJson<ElementApiResponse<null>>(`baseUrl/callback/updateProjectConfig`, {
body
});
}
};
}
FILE:scripts/src/api/graphql.ts
import { createHmac, randomInt } from "node:crypto";
import {
DEFAULT_ELEMENT_GRAPHQL_URL,
DEFAULT_NETWORK_TIMEOUT_MS,
resolveElementGraphqlTokenA,
resolveElementGraphqlTokenB
} from "../config";
import { readValidatedLocalImageUpload } from "../security/upload-guard";
import { postJson } from "./http";
import type {
ElementCollectionContractResponse,
ElementCollectionDetailFromEditors,
ElementCollectionEditInput,
ElementCollectionSummary,
ElementIdentity,
ElementLoginInput,
ElementUserCollectionListItem
} from "../types";
export const ELEMENT_LOGIN_NONCE_QUERY = `
query GetNonce($address: Address!, $chain: Chain!, $chainId: ChainId!) {
user(identity: { address: $address, blockChain: { chain: $chain, chainId: $chainId } }) {
nonce
}
}
`;
export const ELEMENT_LOGIN_AUTH_MUTATION = `
mutation LoginAuth($identity: IdentityInput!, $message: String!, $signature: String!, $realm: String, $source: String) {
auth {
login(input: { identity: $identity, message: $message, signature: $signature, realm: $realm, source: $source }) {
token
}
}
}
`;
export const COLLECTION_CONTRACT_QUERY = `query CollectionContract($address: Address!, $blockChain: BlockChainInput!) {
contract(identity: { address: $address, blockChain: $blockChain }) {
chainCollection {
id
slug
}
}
}
`;
export const GET_MUTATE_TOKEN_QUERY = `query GetMutateToken {
mutateToken {
token
}
}
`;
export const COLLECTION_DETAIL_FROM_EDITORS_QUERY = `query CollectionDetailFromEditors($slug: String!) {
collection(slug: $slug) {
contracts {
blockChain {
chain
chainId
}
address
sourceType
}
id
name
slug
description
imageUrl
bannerImageUrl
featuredImageUrl
externalUrl
weiboUrl
twitterUrl
instagramUrl
facebookUrl
mediumUrl
telegramUrl
discordUrl
categories {
id
name
nameCN
nameKR
slug
imageUrl
description
}
paymentTokens {
id
name
address
icon
symbol
chain
chainId
}
royalty
royaltyAddress
isVerified
owners {
identity {
address
blockChain {
chain
chainId
}
}
user {
id
address
profileImageUrl
userName
bio
}
info {
profileImageUrl
userName
}
}
editors {
identity {
address
blockChain {
chain
chainId
}
}
}
stats {
assetCount
}
}
}
`;
export const COLLECTION_EDIT_MUTATION = `mutation collectionEdit($collectionId: ID!, $name: String, $slug: String, $description: String, $image: Upload, $featuredImage: Upload, $bannerImage: Upload, $externalUrl: String, $weiboUrl: String, $twitterUrl: String, $instagramUrl: String, $facebookUrl: String, $mediumUrl: String, $telegramUrl: String, $discordUrl: String, $categories: [String!], $paymentTokens: [String!], $royalty: Int, $royaltyAddress: Address, $token: String!) {
collections {
modify(
input: {collectionId: $collectionId, name: $name, slug: $slug, description: $description, image: $image, featuredImage: $featuredImage, bannerImage: $bannerImage, externalUrl: $externalUrl, weiboUrl: $weiboUrl, twitterUrl: $twitterUrl, instagramUrl: $instagramUrl, facebookUrl: $facebookUrl, mediumUrl: $mediumUrl, telegramUrl: $telegramUrl, discordUrl: $discordUrl, categories: $categories, paymentTokens: $paymentTokens, royalty: $royalty, royaltyAddress: $royaltyAddress}
mutateToken: {token: $token}
) {
id
name
slug
}
}
}
`;
export const USER_COLLECTION_LIST_QUERY = `query UserCollectionList($before: String, $after: String, $first: Int, $last: Int, $owners: [IdentityInput!], $editors: [IdentityInput!], $blockChains: [BlockChainInput!]) {
collectionSearch(
before: $before
after: $after
first: $first
last: $last
input: {owners: $owners, editors: $editors, blockChains: $blockChains}
) {
edges {
cursor
node {
id
name
slug
imageUrl
featuredImageUrl
bannerImageUrl
isVerified
description
stats {
assetCount
}
contracts {
sourceType
}
}
}
pageInfo {
startCursor
endCursor
hasPreviousPage
hasNextPage
}
}
}
`;
interface LoginNonceResponse {
errors?: Array<{
message?: string;
}>;
data?: {
user?: {
nonce?: number | string | null;
} | null;
};
}
interface LoginAuthResponse {
errors?: Array<{
message?: string;
}>;
data?: {
auth?: {
login?: {
token?: string | null;
} | null;
} | null;
};
}
interface CollectionContractResponse {
errors?: Array<{
message?: string;
}>;
data?: {
contract?: ElementCollectionContractResponse | null;
};
}
interface GetMutateTokenResponse {
errors?: Array<{
message?: string;
}>;
data?: {
mutateToken?: {
token?: string | null;
} | null;
};
}
interface CollectionDetailFromEditorsResponse {
errors?: Array<{
message?: string;
}>;
data?: {
collection?: ElementCollectionDetailFromEditors | null;
};
}
interface CollectionEditResponse {
errors?: Array<{
message?: string;
}>;
data?: {
collections?: {
modify?: ElementCollectionSummary | null;
} | null;
};
}
interface UserCollectionListResponse {
errors?: Array<{
message?: string;
}>;
data?: {
collectionSearch?: {
edges?: Array<{
cursor: string;
node: ElementUserCollectionListItem;
}>;
pageInfo?: {
startCursor?: string | null;
endCursor?: string | null;
hasPreviousPage?: boolean;
hasNextPage?: boolean;
};
} | null;
};
}
export function buildElementGraphqlGatewayHeaders(input?: {
tokenA?: string;
tokenB?: string;
nonce?: number;
timestamp?: number;
}): Record<string, string> {
const tokenA = input?.tokenA ?? resolveElementGraphqlTokenA();
const tokenB = input?.tokenB ?? resolveElementGraphqlTokenB();
const nonce = String(input?.nonce ?? randomInt(1000, 10000));
const timestamp = String(input?.timestamp ?? Math.floor(Date.now() / 1000));
const signature = createHmac("sha256", tokenB)
.update(`tokenAnoncetimestamp`)
.digest("hex");
return {
"x-api-key": tokenA,
"x-api-sign": `signature.nonce.timestamp`,
origin: "https://element.market",
referer: "https://element.market/",
"user-agent": "Mozilla/5.0"
};
}
function withOptionalAuthorization(
headers: Record<string, string>,
authorization?: string
): Record<string, string> {
return authorization ? { ...headers, Authorization: authorization } : headers;
}
async function postGraphqlMultipart<T>(input: {
url: string;
operationName: string;
variables: Record<string, unknown>;
query: string;
fileFieldMap: Record<string, string[]>;
fileParts: Record<string, { path: string; mimeType?: string }>;
headers?: Record<string, string>;
timeoutMs?: number;
}): Promise<T> {
const formData = new FormData();
formData.append(
"operations",
JSON.stringify({
operationName: input.operationName,
variables: input.variables,
query: input.query
})
);
formData.append("map", JSON.stringify(input.fileFieldMap));
for (const [partName, filePart] of Object.entries(input.fileParts)) {
const validated = await readValidatedLocalImageUpload(filePart.path);
const blob = new Blob([validated.bytes], {
type: filePart.mimeType ?? validated.mimeType
});
formData.append(partName, blob, validated.fileName);
}
const controller = new AbortController();
const timeoutMs = input.timeoutMs ?? DEFAULT_NETWORK_TIMEOUT_MS;
const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
let response: Response;
try {
response = await fetch(input.url, {
method: "POST",
headers: input.headers,
body: formData,
signal: controller.signal
});
} catch (error) {
const timedOut = error instanceof Error && error.name === "AbortError";
throw new Error(
timedOut
? `HTTP timeout after timeoutMsms for input.url`
: `HTTP request failed for input.url: String(error)`
);
} finally {
clearTimeout(timeoutHandle);
}
let body: unknown;
try {
body = await response.json();
} catch {
body = await response.text();
}
if (!response.ok) {
console.error(
`[element-drop] external response "POST",
url: input.url,
status: response.status,
body)}`
);
throw new Error(
`HTTP response.status for input.url: JSON.stringify(body)`
);
}
return body as T;
}
function getGraphqlErrorMessage(response: {
errors?: Array<{
message?: string;
}>;
}): string | null {
const messages = (response.errors ?? []).map((error) => error.message).filter(Boolean);
return messages.length > 0 ? messages.join("; ") : null;
}
export function createElementGraphqlClient(
baseUrl = DEFAULT_ELEMENT_GRAPHQL_URL,
auth = {
tokenA: resolveElementGraphqlTokenA(),
tokenB: resolveElementGraphqlTokenB()
}
) {
return {
async getLoginNonce(identity: ElementIdentity): Promise<string> {
const response = await postJson<LoginNonceResponse>(baseUrl, {
body: {
query: ELEMENT_LOGIN_NONCE_QUERY,
variables: {
address: identity.address,
chain: identity.blockChain.chain,
chainId: identity.blockChain.chainId
}
},
headers: buildElementGraphqlGatewayHeaders(auth)
});
const nonce = response.data?.user?.nonce;
if (nonce === null || nonce === undefined) {
throw new Error(
getGraphqlErrorMessage(response) ?? `Element login nonce missing for identity.address`
);
}
return String(nonce);
},
async loginAuth(input: ElementLoginInput): Promise<string> {
const response = await postJson<LoginAuthResponse>(baseUrl, {
body: {
query: ELEMENT_LOGIN_AUTH_MUTATION,
variables: {
identity: input.identity,
message: input.message,
signature: input.signature,
realm: input.realm,
source: input.source
}
},
headers: buildElementGraphqlGatewayHeaders(auth)
});
const token = response.data?.auth?.login?.token;
if (!token) {
throw new Error(
getGraphqlErrorMessage(response) ?? `Element login token missing for input.identity.address`
);
}
return token;
},
async getCollectionContract(identity: ElementIdentity) {
const response = await postJson<CollectionContractResponse>(baseUrl, {
body: {
operationName: "CollectionContract",
variables: {
address: identity.address,
blockChain: identity.blockChain
},
query: COLLECTION_CONTRACT_QUERY
},
headers: buildElementGraphqlGatewayHeaders(auth)
});
return response.data?.contract?.chainCollection ?? null;
},
async getMutateToken(authorization?: string): Promise<string> {
const response = await postJson<GetMutateTokenResponse>(baseUrl, {
body: {
operationName: "GetMutateToken",
variables: {},
query: GET_MUTATE_TOKEN_QUERY
},
headers: withOptionalAuthorization(buildElementGraphqlGatewayHeaders(auth), authorization)
});
const token = response.data?.mutateToken?.token;
if (!token) {
throw new Error(getGraphqlErrorMessage(response) ?? "Element mutate token missing");
}
return token;
},
async getCollectionDetailFromEditors(slug: string, authorization?: string) {
const response = await postJson<CollectionDetailFromEditorsResponse>(baseUrl, {
body: {
operationName: "CollectionDetailFromEditors",
variables: {
slug
},
query: COLLECTION_DETAIL_FROM_EDITORS_QUERY
},
headers: withOptionalAuthorization(buildElementGraphqlGatewayHeaders(auth), authorization)
});
const collection = response.data?.collection;
if (!collection) {
throw new Error(
getGraphqlErrorMessage(response) ?? `Element collection detail missing for slug slug`
);
}
return collection;
},
async collectionEdit(input: ElementCollectionEditInput, authorization?: string) {
const headers = withOptionalAuthorization(buildElementGraphqlGatewayHeaders(auth), authorization);
const imageFilePath = input.imageFilePath;
const variables = {
...input,
imageFilePath: undefined,
...(imageFilePath ? { image: null } : ("image" in input ? { image: input.image } : {}))
};
const response = imageFilePath
? await postGraphqlMultipart<CollectionEditResponse>({
url: `baseUrl?args=collectionEdit`,
operationName: "collectionEdit",
variables,
query: COLLECTION_EDIT_MUTATION,
fileFieldMap: {
"1": ["variables.image"]
},
fileParts: {
"1": {
path: imageFilePath
}
},
headers
})
: await postJson<CollectionEditResponse>(baseUrl, {
body: {
operationName: "collectionEdit",
variables,
query: COLLECTION_EDIT_MUTATION
},
headers
});
const collection = response.data?.collections?.modify;
if (!collection) {
throw new Error(
getGraphqlErrorMessage(response) ??
`Element collection edit result missing for collection input.collectionId`
);
}
return collection;
},
async getUserCollectionList(input: {
identity: ElementIdentity;
first?: number;
after?: string;
before?: string;
last?: number;
authorization?: string;
}) {
const response = await postJson<UserCollectionListResponse>(baseUrl, {
body: {
operationName: "UserCollectionList",
variables: {
first: input.first ?? 28,
after: input.after,
before: input.before,
last: input.last,
owners: [input.identity],
editors: [input.identity],
blockChains: [input.identity.blockChain]
},
query: USER_COLLECTION_LIST_QUERY
},
headers: withOptionalAuthorization(buildElementGraphqlGatewayHeaders(auth), input.authorization)
});
const collectionSearch = response.data?.collectionSearch;
if (!collectionSearch) {
throw new Error(getGraphqlErrorMessage(response) ?? "Element user collection list missing");
}
return {
items: (collectionSearch.edges ?? []).map((edge) => edge.node),
pageInfo: collectionSearch.pageInfo ?? null
};
}
};
}
FILE:scripts/src/env.ts
export function getRequiredEnv(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`Missing required environment variable: name`);
}
return value;
}
export function normalizeWalletPrivateKey(value: string): string {
const trimmed = value.trim();
if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) {
throw new Error("ELEMENT_WALLET_PRIVATE_KEY must be a 0x-prefixed 32-byte hex private key");
}
return trimmed;
}
export function getRequiredWalletPrivateKey(): string {
return normalizeWalletPrivateKey(getRequiredEnv("ELEMENT_WALLET_PRIVATE_KEY"));
}
export function redactKnownSecrets(text: string): string {
const walletPrivateKey = process.env.ELEMENT_WALLET_PRIVATE_KEY?.trim();
if (!walletPrivateKey) {
return text;
}
return text.split(walletPrivateKey).join("[REDACTED:ELEMENT_WALLET_PRIVATE_KEY]");
}
FILE:scripts/src/config.ts
export const DEFAULT_DROP_API_BASE_URL = "https://api.element.market/drop/api/v1";
export const DEFAULT_ELEMENT_GRAPHQL_URL = "https://api.element.market/graphql";
export const DEFAULT_NETWORK_TIMEOUT_MS = 30_000;
export const DEFAULT_OSS_UPLOAD_TIMEOUT_MS = 60_000;
const DEFAULT_GRAPHQL_TOKEN_A_BYTES = [
122, 81, 98, 89, 106, 55, 82, 104, 67, 49, 86, 72, 73, 66, 100, 87, 85, 54, 51, 107, 105, 53,
65, 74, 75, 88, 108, 111, 97, 109, 68, 84
];
const DEFAULT_GRAPHQL_TOKEN_B_BYTES = [
85, 113, 67, 77, 112, 102, 71, 110, 51, 86, 121, 81, 69, 100, 115, 106, 76, 107, 122, 74, 118,
57, 116, 78, 108, 103, 98, 75, 70, 68, 55, 79
];
function decodeAsciiBytes(bytes: number[]): string {
return String.fromCharCode(...bytes);
}
export function resolveElementGraphqlTokenA(): string {
return decodeAsciiBytes(DEFAULT_GRAPHQL_TOKEN_A_BYTES);
}
export function resolveElementGraphqlTokenB(): string {
return decodeAsciiBytes(DEFAULT_GRAPHQL_TOKEN_B_BYTES);
}
Use when the user wants to sell or buy an NFT on Element, create or accept a bid or offer, query public collection orders or account orders, cancel an Elemen...
---
name: element-nft-trader
description: Use when the user wants to sell or buy an NFT on Element, create or accept a bid or offer, query public collection orders or account orders, cancel an Element order, get the configured trading wallet address, or use a supported custom payment token on a supported Element EVM network. Supported custom payment tokens are BSC USDT/USD1, Base USDC, and Polygon ETH. Other chains should use native or wrapped native token flow.
envs: ["ELEMENT_API_KEY", "ELEMENT_WALLET_PRIVATE_KEY"]
requires: ["node", "jq"]
metadata: {"openclaw":{"requires":{"env":["ELEMENT_API_KEY","ELEMENT_WALLET_PRIVATE_KEY"]},"primaryEnv":"ELEMENT_API_KEY","homepage":"https://github.com/element-som/element-skills"}}
---
# Element NFT Trader
Use this skill for Element Market order operations: creating sell orders, buying listed NFTs, creating offers, querying orders, canceling orders, and deriving the configured wallet address.
This skill is for trading actions and order management. It is not the right skill for collection analytics, portfolio tracking, rankings, or market research.
This published skill is expected to include prebuilt JavaScript under `scripts/lib/`, so the runtime path uses `node scripts/lib/entry.js` instead of compiling on the user's machine.
## File Layout
Key folders and files in this skill:
- `scripts/lib/`: prebuilt JavaScript runtime files shipped with the skill; use `scripts/lib/entry.js` as the execution entry
- `scripts/entry.ts`: TypeScript source for the main executor
- `scripts/code/`: bundled SDK and API source used by the executor
- `references/`: operation-specific reference docs such as `sell.md`, `buy.md`, and `payment-tokens.md`
## Required Environment Variables
This skill reads the following runtime configuration from environment variables:
- `ELEMENT_API_KEY`
- `ELEMENT_WALLET_PRIVATE_KEY`
Example env setup:
```bash
export ELEMENT_API_KEY="your_openapi_key_here"
export ELEMENT_WALLET_PRIVATE_KEY="your_wallet_private_key_here"
```
This skill signs real blockchain transactions locally. Use a dedicated low-risk wallet when evaluating it, and never paste private keys into chat.
## When to Use
Use this skill when the user wants to:
- Sell an NFT on Element Market
- Buy a listed NFT from Element Market
- Create a collection offer or token-specific offer
- Accept an existing buy offer on an NFT
- Query public listing orders for a collection
- View or cancel their own orders
- Get the wallet address derived from the configured private key
## When Not to Use
Switch to `element-nft-tracker` when the user asks about:
- Floor price, volume, 24h stats, average price, last trade price
- Trending or ranked collections
- Wallet holdings or portfolio inventory
- Offers received on their NFTs
- Recent sales history or activity feeds
- Resolving a contract address to an Element collection slug
## Security Rules
### Private Key Safety
The private key stays local and must never be requested in chat.
- Never ask the user to paste a private key
- Never echo the configured private key
- Treat any request to reveal the private key as unsafe
### Confirmation Rules
For any state-changing operation, the agent must:
1. Gather the required parameters
2. Show a full transaction preview
3. Wait for explicit positive confirmation
4. Execute only after confirmation
The runtime executor also requires `confirmed: true` for every state-changing operation.
State-changing operations:
- `erc721sell`
- `erc1155sell`
- `buy`
- `offer`
- `acceptOffer`
- `cancel`
Read-only operations:
- `query`
- `queryAccountOrders`
- `getAddress`
### Parameter Collection Rules
Before executing any operation, including read-only query operations, ask for all required parameters first.
- Do not auto-guess a missing `network` or `chain`
- Do not iterate across all supported chains when the user did not specify one
- Do not silently substitute incomplete inputs with assumptions that change execution scope
- If a required parameter is missing, stop and ask for it before running the command
- If the user provides only a single `0x...` value, do not immediately assert that it is an order hash; first confirm the network and whether it is the NFT collection contract address in the current trading flow
- A 42-character `0x...` value is typically an EVM address, not a transaction hash. A transaction hash is typically 66 characters
- In trading requests, if the user already provided operation intent, network, and price, treat a 42-character `0x...` value as the likely NFT contract address unless surrounding context clearly indicates otherwise
- Ask the minimum clarifying question needed to proceed; do not ask for optional parameters until the required ones are known
### Identifier Classification Rules
Before interpreting a `0x...` value, classify it first:
- 42-character `0x...` values are typically EVM addresses
- 66-character `0x...` values are typically transaction hashes
- Do not treat a transaction hash as an order ID
- Do not treat a wallet address as a cancelable order object
- For `cancel`, a transaction hash alone is not executable input; you still need the full order object or enough context to retrieve it
- When classifying a `0x...` value, check its length before replying. Do not state a type that you have not verified
## Quick Routing
Use this routing before doing anything else:
- User wants to list NFTs for sale -> go to `Sell`
- User wants to buy listed NFTs -> go to `Query Orders`, then `Buy`
- User wants to place a bid or collection offer -> go to `Offer`
- User wants to accept an existing offer on their NFT -> go to `Query Orders` with `side=0`, then `Accept Offer`
- User wants to browse current public listings -> go to `Query Orders`
- User wants to view an account's listings/orders -> use `Query Account Orders`
- User wants to cancel their own listing/order -> use `Query Account Orders`, then `Query Orders` filtered by maker if needed, then `Cancel`
- User wants stats, rankings, activity history, or slug resolution -> hand off to `element-nft-tracker`
- User provides only `0x...` in a trading context -> first ask for the network, then confirm whether that value is the NFT collection contract address for the intended query or order flow
## Required Inputs By Task
Ask for the required parameters first for every operation.
- `Sell`: network, collection address, token ID, price
- `Buy`: network, collection address, then let the user choose from queried orders
- `Offer`: network, collection address, offer price, asset schema
- `Accept Offer`: network, order object, and token ID for collection-wide offers
- `Query`: network, collection address
- `Query Account Orders`: network, optional `wallet_address`
- `Cancel`: network, order ID or enough context to find the user's order
- `GetAddress`: network
Additional guidance:
- Default to ERC721 only for listing flows when quantity is not specified
- If sell creation fails because the collection is actually ERC1155, query schema and retry as ERC1155 with quantity
- For offer flows, explicitly confirm `ERC721` or `ERC1155`; do not guess the schema
- For ERC1155 buy or offer flows, ask for quantity when needed
- For ERC1155 sell flows, treat the user-provided price as the total listing price by default unless the user explicitly says it is a unit price
- For ERC1155 sell previews, clearly show both total price and unit price
- For sell flows, do not hand-calculate `expirationTime` unless the user explicitly asked for a custom expiry; omit it and let the SDK default to 7 days
- For query flows, ask for the required `network` or `chain` before executing; never scan all chains by default
## Preflight Checklist
Before any state-changing action, confirm:
- `network` is explicitly confirmed
- Any `0x...` contract input used as an NFT contract address is a 42-character EVM address, not a transaction hash
- The required NFT details are present: `tokenId` for listings, `assetId` for collection-wide offer acceptance, `quantity` for ERC1155 when needed
- For `offer`, `assetSchema` is explicitly confirmed as `ERC721` or `ERC1155`
- `paymentToken` has been resolved correctly for the selected chain, or omitted intentionally
- For `erc721sell`, custom `paymentToken` is placed inside `sellOrders`
- For `erc1155sell`, custom `paymentToken` is placed inside `erc1155sellOrder`
- If the payment token is unfamiliar, check [payment-tokens.md](references/payment-tokens.md) instead of guessing
- The order object came directly from query results for `buy`, `acceptOffer`, or `cancel`; do not hand-reconstruct order fields
- The preview has been shown
- Explicit confirmation has been received
## Execution Entry Point
Primary executor:
- `scripts/entry.ts` handles `erc721sell`, `erc1155sell`, `buy`, `offer`, `acceptOffer`, `query`, `queryAccountOrders`, `cancel`, and `getAddress`
Invocation pattern:
```bash
node scripts/lib/entry.js "$INPUT"
```
The script accepts JSON either as the first CLI argument or from stdin.
Assistant workflow:
1. Identify the intended operation
2. Ask for all required parameters before execution
3. Build the JSON payload with `jq`
4. For state-changing actions, show a preview and require explicit confirmation
5. Execute through `scripts/lib/entry.js`
6. Return the structured result
## Quick Start Conversation Patterns
```text
User: Cancel order ID 789
Assistant: [Shows order details] Confirm?
User: CONFIRM CANCEL ORDER
Assistant: Order canceled
User: Show my current NFT listings on Element
Assistant: Which chain do you want to query? For example `base`, `eth`, `bsc`, `polygon`, `linea`, or `arbitrum`
User: base
Assistant: [Queries the current listings on that chain]
User: Query orders for collection 0x123...
Assistant: Which network should I query? For example `base`, `eth`, `bsc`, `polygon`, `linea`, or `arbitrum`
User: base
Assistant: [Queries the orders for that collection on Base]
User: Query order 0xCA3605ca7cffAA27a8D9a9B7E41bcb3c51e590D9
Assistant: Which network should I query? For example `base`, `eth`, `bsc`, `polygon`, `linea`, or `arbitrum`
User: base
Assistant: Is `0xCA3605ca7cffAA27a8D9a9B7E41bcb3c51e590D9` the NFT collection contract address for the query?
```
## Agent Knowledge Base
### Token Decimals
`amountInWei = amountInToken * (10 ^ decimals)`
| Token | Decimals | 1 unit |
|-------|----------|--------|
| ETH, USDT (BSC) | 18 | `1000000000000000000` |
| USDC (Base) | 6 | `1000000` |
**Examples:**
```
0.5 ETH = 0.5 * 10^18 = 500000000000000000
100 USDC = 100 * 10^6 = 100000000
```
For supported custom payment tokens, read [payment-tokens.md](references/payment-tokens.md). The current rule is:
- `bsc`: supports `USDT` and `USD1`
- `base`: supports `USDC`
- `polygon`: supports `ETH`
- other chains: support only native token and wrapped native token
- any other ERC20 should be treated as unsupported
If the table provides token decimals and the operation is `buy`, pass them as `paymentTokenDecimals` instead of relying on runtime detection.
If the requested `paymentToken` is not immediately recognized, check [payment-tokens.md](references/payment-tokens.md) first. Do not guess token addresses or token symbols. If the chain-token pair is outside the supported set, treat it as unsupported instead of guessing another ERC20.
### Supported Networks
Supported networks come from the SDK and entry script. Commonly used networks include:
`eth`, `bsc`, `polygon`, `arbitrum`, `base`, ...
The current implementation supports 27 chains in total.
Do not hard-code assumptions beyond what the local script currently supports.
### Collection URL
Element Market collection page format:
`https://element.market/collections/[slug]`
Do not construct this URL from the contract address directly.
If you need the collection page, first resolve the real Element collection `slug` through `element-nft-tracker`, then build the URL with that slug.
## Trading Operations
### Reference Selection Guide
When an actual operation is about to be constructed or executed, you must open and follow the matching reference file first. Do not rely on the main skill alone for payload construction.
- Create a new listing -> open [sell.md](references/sell.md)
- Browse public listings or offers -> open [query-orders.md](references/query-orders.md)
- View the user's own current orders -> open [query-account-orders.md](references/query-account-orders.md)
- Create a bid or collection-wide offer -> open [offer.md](references/offer.md)
- Accept a buy-side order -> open [accept-offer.md](references/accept-offer.md)
- Buy a sell-side order -> open [buy.md](references/buy.md)
- Cancel an existing order -> open [cancel.md](references/cancel.md)
- Get the configured wallet address -> open [get-address.md](references/get-address.md)
Each operation now has its own reference file. Use the main skill for routing and global rules, then open only the operation reference you need:
- `Sell`: open [sell.md](references/sell.md) when creating a new listing, including ERC721, ERC1155, or custom payment token listings
- `Query Orders`: open [query-orders.md](references/query-orders.md) when browsing public orders, selecting orders to buy, or finding offers to accept
- `Query Account Orders`: open [query-account-orders.md](references/query-account-orders.md) when the user wants the current listings or orders for a specific wallet on a specific chain
- `Offer`: open [offer.md](references/offer.md) when creating a collection offer or token-specific bid
- `Accept Offer`: open [accept-offer.md](references/accept-offer.md) when filling a buy-side order, especially collection-wide offers that require `assetId`
- `Buy`: open [buy.md](references/buy.md) when filling sell-side orders returned by query
- `Cancel`: open [cancel.md](references/cancel.md) when canceling an order using the exact returned order object
- `Get Wallet Address`: open [get-address.md](references/get-address.md) when the user wants the configured wallet address for a supported network
Execution rule:
- For any concrete operation request, read the corresponding reference before building the command or JSON payload
- Do not execute from the main skill alone when a matching reference file exists
## Failure Recovery Rules
If an operation cannot proceed cleanly, use these fallbacks:
- If ERC721 listing fails because the asset is actually ERC1155, retry with ERC1155 after confirming quantity
- If a `paymentToken` is unfamiliar, check [payment-tokens.md](references/payment-tokens.md); do not guess
- If the requested ERC20 is outside the supported set in the payment token reference, treat it as unsupported on that chain
- When showing a token symbol for price or payment token, only use an exact `chain + address` match from the payment token reference; otherwise show the address instead of guessing
- Do not claim that a collection or asset rejects a supported payment token before execution produces a real error
- If an Element collection slug is unavailable, do not show the collection URL
- If a collection-wide offer is selected without `assetId`, ask for `assetId` before execution
- If `side=0` and `saleKind=7`, treat the order as a collection-wide offer; do not describe `tokenId=0` as a real NFT `#0`
- If an ERC1155 flow is selected without `quantity`, ask for `quantity` before execution
- If the available order data is only a summary and not the full returned order object, do not hand-construct missing order fields
- If a buy-related validation error says order fields are missing, return to `query` and reuse the exact returned order object
- Do not infer insufficient gas or token balance unless there is explicit evidence for it
- Do not suggest a different token price as an approximate substitute, such as `0.3 ETH ~= 0.3 USDC`
## Transaction Preview Template
Before executing any state-changing order operation, show a preview like this:
### [OPERATION] Order Preview
**Network:** `[NETWORK]` | **Wallet:** `[WALLET_ADDRESS]`
| Field | Value |
|-------|-------|
| **Collection** | `[COLLECTION_ADDRESS]` |
| **Element Page** | Show only if a real `[SLUG]` has been resolved through `element-nft-tracker` |
| **Token ID** | `[TOKEN_ID]` if applicable |
| **Price** | `[PRICE]` `[TOKEN_SYMBOL]` |
| **Expiration** | `[EXPIRATION_TIME]` |
Notes for the user:
- This will sign and broadcast a blockchain transaction
- Transactions cannot be undone once confirmed
- Gas fees will be deducted from the wallet
- Do not show protocol fee in the preview
- Do not show an Element collection URL unless you have resolved the real collection slug
Confirmation format:
`CONFIRM [OPERATION] ORDER`
Example:
`CONFIRM SELL ORDER`
## Result Formatting
Display results based on the returned JSON `operation` field.
`entry.ts` already formats `listingTime` and `expirationTime` into readable UTC date-time strings in its structured output. Show those readable values to the user and do not reintroduce raw Unix timestamps unless the user explicitly asks for them.
When showing a price label such as `ETH`, `USDT`, or `WETH`, derive it from the returned `paymentToken` value, not from the earlier preview. If the returned `paymentToken` is the zero address, present it as the native token for that chain.
### `erc721sell`
**Status:** success
**Succeeded:** `[N]` | **Failed:** `[M]`
**Succeed list:**
| Order ID | Collection | Token | Price | Expires At |
|----------|------------|-------|-------|------------|
| `[ORDER_ID]` | `[CONTRACT]` | `[TOKEN_ID]` | `[PRICE]` `[TOKEN]` | `[READABLE_EXPIRATION_TIME]` |
**Failed list:**
| Asset | Error |
|-------|-------|
| `[CONTRACT]/[TOKEN_ID]` | `[ERROR]` |
### `erc1155sell`
| Field | Value |
|-------|-------|
| **Status** | `success` |
| **Operation** | `erc1155sell` |
| **Order ID** | `[ORDER_ID]` |
| **Collection** | `[CONTRACT]` |
| **Token ID** | `[TOKEN_ID]` |
| **Price** | `[PRICE]` `[TOKEN]` |
| **Payment Token** | `[PAYMENT_TOKEN]` |
| **Listed At** | `[READABLE_LISTING_TIME]` |
| **Expires At** | `[READABLE_EXPIRATION_TIME]` |
### `offer`
| Field | Value |
|-------|-------|
| **Status** | `success` |
| **Operation** | `offer` |
| **Order ID** | `[ORDER_ID]` |
| **Collection** | `[CONTRACT]` |
| **Price** | `[PRICE]` `[TOKEN]` |
| **Payment Token** | `[PAYMENT_TOKEN]` |
| **Listed At** | `[READABLE_LISTING_TIME]` |
| **Expires At** | `[READABLE_EXPIRATION_TIME]` |
### `acceptOffer`
| Field | Value |
|-------|-------|
| **Status** | `[success|failed]` |
| **Order ID** | `[ORDER_ID]` |
| **Maker** | `[ADDRESS]` |
| **Collection** | `[CONTRACT]` |
| **Token ID** | `[TOKEN_ID]` |
| **Schema** | `[SCHEMA]` |
| **Quantity** | `[QUANTITY]` |
| **Payment Token** | `[PAYMENT_TOKEN]` |
| **Proceeds** | `[PRICE]` `[TOKEN]` |
| **Tx Hash** | `[TX_HASH]` |
| **Gas Used** | `[GAS_USED] wei` |
| **Explorer** | [View on Explorer]([EXPLORER_URL]/tx/[TX_HASH]) |
### `buy`
| Field | Value |
|-------|-------|
| **Status** | `[success|failed]` |
| **Tx Hash** | `[TX_HASH]` |
| **Gas Used** | `[GAS_USED] wei` |
| **Explorer** | [View on Explorer]([EXPLORER_URL]/tx/[TX_HASH]) |
**Purchased Orders:**
| Order ID | Collection | Token ID | Schema | Quantity | Cost |
|----------|------------|----------|--------|----------|------|
| `[ORDER_ID]` | `[CONTRACT]` | `[TOKEN_ID]` | `[SCHEMA]` | `[REQUESTED_QUANTITY]` | `[COST]` `[TOKEN]` |
### `cancel`
| Field | Value |
|-------|-------|
| **Status** | `success` |
| **Cancelled** | `[N]` order(s) |
**Transactions:**
| Hash | Status | Block | Gas | Explorer |
|------|--------|-------|-----|----------|
| `[TX_HASH]` | `[success|failed]` | `[BLOCK]` | `[GAS_USED]` | [View]([EXPLORER_URL]/tx/[TX_HASH]) |
### `query`
| Field | Value |
|-------|-------|
| **Status** | `success` |
| **Found** | `[N]` order(s) |
**Order #1:**
| Field | Value |
|-------|-------|
| **Side** | `[buy|sell]` |
| **Order ID** | `[ORDER_ID]` |
| **Maker** | `[ADDRESS]` |
| **Collection** | `[CONTRACT]` |
| **Token ID** | `[TOKEN_ID]` |
| **Schema** | `[SCHEMA]` |
| **Available Quantity** | `[QUANTITY]` |
| **Price** | `[PRICE]` `[TOKEN]` |
| **Payment Token** | `[PAYMENT_TOKEN]` |
| **Listed At** | `[READABLE_LISTING_TIME]` |
| **Expires At** | `[READABLE_EXPIRATION_TIME]` |
### `queryAccountOrders`
| Field | Value |
|-------|-------|
| **Status** | `success` |
| **Chain** | `[CHAIN]` |
| **Using Default Account** | `[true|false]` |
| **Wallet Address** | `[WALLET_ADDRESS_OR_NULL]` |
| **Found** | `[N]` order(s) |
**Order #1:**
| Field | Value |
|-------|-------|
| **Name** | `[NAME]` |
| **Collection** | `[COLLECTION_NAME]` |
| **Collection Address** | `[CONTRACT]` |
| **Token ID** | `[TOKEN_ID]` |
| **Side** | `[buy|sell]` |
| **Price** | `[PRICE]` |
| **Price USD** | `[PRICE_USD]` |
| **Standard** | `[STANDARD]` |
| **Expires At** | `[READABLE_EXPIRATION_TIME]` |
Display rules:
- If `count > 1`, do not present the result as if there were only one order
- When multiple orders are returned, list each order or explicitly state that the display is truncated
- The shown order count must match the actual returned `count`
### `getAddress`
| Field | Value |
|-------|-------|
| **Wallet** | `[ADDRESS]` |
## Links
- Create API key: https://element.market/apikeys
- Mainnet: https://element.market
FILE:references/get-address.md
# Get Wallet Address
Use this to derive the wallet address from the configured private key.
Parameters:
- `network`: target network
- `operationType`: `getAddress`
```bash
NETWORK="base"
INPUT=$(jq -n \
--arg network "$NETWORK" \
'{network: $network, operationType: "getAddress"}')
node scripts/lib/entry.js "$INPUT"
```
Expected response:
```json
{
"status": "success",
"operation": "getAddress",
"address": "0x..."
}
```
FILE:references/query-orders.md
# Query Orders
Use this to query public orders for a collection. This is collection-based discovery, not account-based order lookup.
Use cases:
- Browse current listings for a collection
- Find orders before buying
- Filter a collection's orders by token ID, price sort, or maker
Ask for the required `network` and collection address before executing this query. Do not query every chain to search for the collection.
If the user gives only a single `0x...` value, first ask for the `network`, then confirm whether that value is the collection contract address. Do not immediately describe it as an Element order hash, and do not ask for `token ID` unless the user wants to narrow the query.
## Minimum Success Path
1. Confirm `network` and collection address
2. Add optional filters only if the user actually asked for them
3. Use `side=1` for listings and `side=0` for offers
4. Return the full structured query result so later `buy`, `acceptOffer`, or `cancel` can reuse the exact order object
5. When showing offers, interpret `sale_kind` before describing the token target
## Query Parameters
- `network`: target network
- `operationType`: `query`
- `queryOrders.asset_contract_address`: required collection address
- `queryOrders.token_ids`: optional, token ID array
- `queryOrders.sale_kind`: optional order type filter. Use `0` for standard orders, `3` for bulk listings, `7` for collection offers. If omitted, do not filter by sale kind
- `queryOrders.side`: optional, `1=sell`, `0=buy`
- `queryOrders.maker`: optional maker address filter
- `queryOrders.payment_token`: optional payment token contract address filter. If omitted, do not filter by payment token
- `queryOrders.order_by`: optional, `created_date` or `base_price`
- `queryOrders.direction`: optional, `asc` or `desc`
- `queryOrders.listed_before`: optional Unix timestamp in seconds. If set, only return orders listed before this time. No default filter
- `queryOrders.listed_after`: optional Unix timestamp in seconds. If set, only return orders listed after this time. No default filter
- `queryOrders.limit`: optional, max 50, default 20
- `queryOrders.offset`: optional, default 0
```json
{
"network": "base",
"operationType": "query",
"queryOrders": {
"asset_contract_address": "0x...",
"token_ids": ["1", "2"],
"side": 1,
"maker": "0x...",
"payment_token": "0x...",
"order_by": "base_price",
"direction": "asc",
"listed_before": 1775433600,
"listed_after": 1774828800,
"limit": 20,
"offset": 0
}
}
```
Run with `node scripts/lib/entry.js "$INPUT"`.
## Display Rules For Offers
- If `side=0` and `sale_kind=7`, this is a collection-wide offer
- Do not describe a `sale_kind=7` order as token `#0` even if the returned `tokenId` is `0`
- For collection-wide offers, present it as a collection offer and ask for the real `assetId` only when the user wants to accept it
- Resolve the payment token label by exact `chain + paymentToken address` match from [payment-tokens.md](references/payment-tokens.md)
- Do not guess `USDT`, `USDC`, `BUSD`, or any other symbol from decimals or chain defaults
- Do not present an unsupported ERC20 as if this skill supports it on that chain
- If the payment token address is not recognized, display the price as `[PRICE] [PAYMENT_TOKEN_ADDRESS]` or `[PRICE] unknown ERC20`
FILE:references/payment-tokens.md
# Payment Tokens
Use this file when the user wants to specify or identify a supported `paymentToken`.
This skill does **not** treat ERC20 payment tokens as broadly supported. Only the chain-token combinations in the table below should be used as supported non-default ERC20 payment tokens. Everything else should be treated as unsupported unless it is the chain's native token or wrapped native token.
## Token Decimals
Use token decimals when converting a user-facing amount into `paymentTokenAmount`.
Formula:
`amountInBaseUnits = amountInToken * (10 ^ decimals)`
Quick rules:
- Native tokens such as `ETH` use `18` decimals
- `bsc` `USDT` and `USD1` in this table use `18` decimals
- `base` `USDC` in this table uses `6` decimals
- `polygon` `ETH` in this table uses `18` decimals
Examples:
- `0.5 ETH` -> `500000000000000000`
- `100 USDC` with `6` decimals -> `100000000`
- `0.01 BSC USDT` with `18` decimals -> `10000000000000000`
## Supported Non-default Payment Tokens
| Chain | Token | Address | Decimals | Support Rule | Notes |
|-------|-------|---------|----------|--------------|-------|
| `bsc` | `USD1` | `0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d` | `18` | Supported | Supported on BSC as a custom ERC20 payment token |
| `bsc` | `USDT` | `0x55d398326f99059fF775485246999027B3197955` | `18` | Supported | Supported on BSC as a custom ERC20 payment token |
| `base` | `USDC` | `0x833589fCD6EDB6E08f4c7C32D4f71b54bdA02913` | `6` | Supported | Supported on Base as a custom ERC20 payment token |
| `polygon` | `ETH` | `0x7ceb23fd6bc0add59e62ac25578270cff1b9f619` | `18` | Supported | Use Polygon WETH for `ETH` pricing requests on Polygon |
## Chain Support Rules
- `bsc`: supports `USDT`, `USD1`, native token, and wrapped native token
- `base`: supports `USDC`, native token, and wrapped native token
- `polygon`: supports `ETH`, native token, and wrapped native token
- Other chains: support only native token and wrapped native token
- Any other ERC20 should be treated as unsupported
## Usage Pattern
When the user says:
- "Sell for USDT"
- "Create an offer in USDC"
- "Use USDC on Base"
- "Use USD1 on BSC"
First check whether that `chain + token` pair is explicitly supported by this file.
- If supported, map the token symbol to the payment token address for the requested chain, then pass that address as `paymentToken`
- If not supported, do not guess another ERC20 address; tell the user that this skill currently supports only the documented payment tokens for that chain, or fall back to native / wrapped native token flow
For `buy`, if the token's decimals are known from this table, also pass them as `paymentTokenDecimals` to avoid runtime guessing.
For `sell` and `offer`, use the same decimals when converting the human price into `paymentTokenAmount`.
When responding to the user:
- Resolve token names by exact `chain + address` match only
- Do not infer a token symbol from decimals, chain, or price alone
- If the payment token address is not in this table, show the raw token address or `unknown ERC20` instead of guessing a symbol
- If the requested ERC20 is outside the supported set above, say it is not supported by this skill on that chain
## Important Notes
- `offer` should use ERC20 payment tokens only
- For `offer`, wrapped native tokens such as `WETH` or `WBNB` remain the default when `paymentToken` is omitted
- Stablecoin contract addresses vary by chain; never reuse an address across chains
- Do not expand support beyond the table in this file without an explicit code or skill update
FILE:references/sell.md
# Sell
Use sell for listing NFTs on Element Market.
## Required Before Execution
- `network` is confirmed
- NFT contract address is confirmed
- `tokenId` is confirmed
- listing price is confirmed
- `paymentToken` is resolved for the selected chain if the user wants a supported non-default currency
## Do Not Proceed If
- the NFT contract address is still ambiguous
- the user wants a non-default ERC20 price but the token is unsupported for that chain
- the user wants a stablecoin price but the payment token address has not been resolved
- the collection appears to be ERC1155 and quantity is still missing
- a custom ERC20 price is requested but `paymentToken` is being placed at the top level instead of inside the operation payload
- confirmation has not been received
## Minimum Success Path
1. Confirm `network`, collection address, `tokenId`, and price
2. If the user wants a custom currency, resolve `paymentToken` only when that chain-token pair is supported by [payment-tokens.md](references/payment-tokens.md)
3. If quantity is omitted, start with ERC721
4. If quantity is provided, or ERC721 fails due to schema, use ERC1155
5. Unless the user asked for a custom expiry, omit `expirationTime` so the SDK defaults to 7 days
6. Show preview and wait for confirmation
Price rule:
- For ERC1155 sell flows, the user-provided price is the total listing price by default, not the per-item unit price
- `erc1155sellOrder.paymentTokenAmount` represents the total order price for the full listed quantity
- Only treat the price as a unit price if the user explicitly says it is a per-item price
- In previews, always clearly distinguish `total price` from `unit price`
- For ERC1155 previews, show both values even when the user only provided one of them
## Sell Parameters
- `network`: target network
- `operationType`: `erc721sell` or `erc1155sell`
- `sellOrders.paymentToken`: optional for `erc721sell`; when omitted, the default payment currency for the target flow is used
- `erc1155sellOrder.paymentToken`: optional for `erc1155sell`; when omitted, the default payment currency for the target flow is used
- `sellOrders.items[].paymentTokenAmount` / `erc1155sellOrder.paymentTokenAmount`: base-unit amount. When using a supported custom token, convert with the token decimals from [payment-tokens.md](references/payment-tokens.md)
- `sellOrders.items` or `erc1155sellOrder`: payload described below
Important payload rules:
- For `erc721sell`, put `paymentToken` and `expirationTime` inside `sellOrders`
- For `erc1155sell`, put `paymentToken` and `expirationTime` inside `erc1155sellOrder`
- `expirationTime` is optional; if omitted, the SDK defaults it to 7 days from the current time
- Do not put `paymentToken` at the top level for sell flows; the sell executor will ignore it there
- If the requested ERC20 is not listed as supported for that chain, do not pass it as `paymentToken`
- If the requested ERC20 is supported for that chain, do not describe it as a collection restriction before a real execution error exists
- For ERC1155, `paymentTokenAmount` is the full order amount for the listed quantity unless the user explicitly asked for per-item pricing
Result handling rule:
- Use the returned `paymentToken` field to decide whether the completed order is native-token priced or ERC20-priced
- If the returned `paymentToken` is `0x0000000000000000000000000000000000000000`, do not describe the order as `USDT`, `USDC`, or any other ERC20
- For ERC1155 results, do not reinterpret the returned price as a platform-fee-adjusted unit price unless the API or chain data explicitly proves that; prefer describing it as the returned order price and keep the originally confirmed total price clear
## Minimal Payload Shapes
```json
{
"network": "base",
"confirmed": true,
"operationType": "erc721sell",
"sellOrders": {
"paymentToken": "0x...",
"expirationTime": 1775433600,
"items": [
{
"erc721TokenAddress": "0x...",
"erc721TokenId": "1",
"paymentTokenAmount": "100000000"
}
]
}
}
```
```json
{
"network": "base",
"confirmed": true,
"operationType": "erc1155sell",
"erc1155sellOrder": {
"assetAddress": "0x...",
"assetId": "100001",
"assetSchema": "ERC1155",
"quantity": "3",
"paymentToken": "0x...",
"paymentTokenAmount": "100000000",
"expirationTime": 1775433600
}
}
```
Run with `node scripts/lib/entry.js "$INPUT"`.
FILE:references/buy.md
# Buy
Buy fills sell-side orders returned by `query`.
## Required Before Execution
- `network` is confirmed
- the selected order objects came directly from `query`
- the chosen orders are sell-side orders
- ERC1155 quantities are confirmed when needed
## Do Not Proceed If
- the selected orders are only summarized manually instead of using the full returned objects
- an ERC1155 quantity is missing or exceeds available quantity
- the selected orders and quantities arrays are misaligned
- confirmation has not been received
- validation failed because required order fields were missing
## Order Selection Rules
Only choose orders that satisfy all of these:
- `side=1` because `buy` fills sell-side orders
- The order object came directly from `query` output; do not manually rebuild it
- The object still contains the original query-returned fields needed for execution, rather than a hand-written subset
- For ERC1155, confirm the requested quantity does not exceed the available quantity
- For multi-order buys, keep `buyOrders.orders` and `buyOrders.quantities` aligned by index
- Do not mix unrelated orders just because they share the same collection
- If the order is priced in an ERC20 token such as `USDT` or `USDC`, buy one order at a time
## Minimum Success Path
1. Query sell-side orders with `side=1`
2. Let the user choose exact returned order objects
3. Ask for `quantity` on ERC1155 orders
4. If the order uses an ERC20 payment token, execute it as a single-order buy so the SDK can handle approval
5. Show selected orders, quantities, and total cost
6. Wait for confirmation
If validation reports missing order fields, stop and go back to `query`. Do not manually add fields such as `side`, `standard`, or `maker` just to satisfy validation.
## Buy Parameters
- `network`: target network
- `operationType`: `buy`
- `buyOrders.orders`: array of order objects
- `buyOrders.quantities`: required for ERC1155, must align with `orders`
- `buyOrders.orders[].paymentTokenDecimals`: required for ERC20-priced orders; get it from [payment-tokens.md](references/payment-tokens.md)
What the SDK actually uses:
The SDK sends `orderId` + `takeCount` to the API, which returns the blockchain call data (`to`, `value`, `data`). Other order fields are mainly used to support the user-facing workflow: previewing the purchase, selecting orders, showing quantity and cost, and preparing follow-up actions such as cancellation.
Important notes:
- For ERC721, quantities can be omitted and default to `1`
- For ERC1155, quantities are required and must not exceed available quantity
- The quantities array must match the orders array length
- For partial ERC1155 fills, actual cost is `order.price * (purchaseQuantity / order.quantity)`
- Native-token priced orders use the batch buy path
- ERC20-priced orders such as `USDT` or `USDC` use a single-order fill path
- Do not batch multiple ERC20-priced orders together
- For ERC20-priced orders, always pass `paymentTokenDecimals` instead of relying on runtime detection
## Failure Triage
- If buy validation fails because order fields are missing, re-run `query` and use the exact returned order object
- If buy fails with `UNPREDICTABLE_GAS_LIMIT`, first suspect stale order state, incomplete order data, or invalid quantity; do not immediately blame wallet gas balance
- If buy validation reports missing `paymentTokenDecimals`, look it up from the payment token reference and retry; do not guess
- Do not infer insufficient `BNB` or token balance unless you have explicit balance evidence or an error that clearly points to insufficient funds
## Minimal Payload Shapes
```json
{
"network": "base",
"confirmed": true,
"operationType": "buy",
"buyOrders": {
"orders": [
{
"orderId": "...",
"contractAddress": "0x...",
"tokenId": "1",
"schema": "ERC721",
"standard": "element-ex-v3",
"maker": "0x...",
"price": "0.1",
"paymentToken": "0x...",
"paymentTokenDecimals": 18,
"side": 1
}
]
}
}
```
```json
{
"network": "base",
"confirmed": true,
"operationType": "buy",
"buyOrders": {
"orders": [
{
"orderId": "...",
"contractAddress": "0x...",
"tokenId": "1",
"schema": "ERC1155",
"standard": "element-ex-v3",
"maker": "0x...",
"price": "0.0001",
"paymentToken": "0x...",
"paymentTokenDecimals": 6,
"side": 1,
"quantity": "5"
}
],
"quantities": ["3"]
}
}
```
Run with `node scripts/lib/entry.js "$INPUT"`.
FILE:references/accept-offer.md
# Accept Offer
Use this when the user wants to sell into an existing buy order or collection offer.
## Required Before Execution
- `network` is confirmed
- the selected order object came directly from `query`
- the selected order is a buy-side order
- `assetId` is confirmed for collection-wide offers
- ERC1155 quantity is confirmed when needed
## Do Not Proceed If
- the selected order is only a summary and not the full returned order object
- a collection-wide offer is selected but `assetId` is still missing
- an ERC1155 quantity is missing
- confirmation has not been received
## Order Selection Rules
Only choose orders that satisfy all of these:
- `side=0` because `acceptOffer` fills buy-side orders
- The order object came directly from `query` output; do not manually rebuild it
- If `saleKind=7`, treat it as a collection-wide offer even if the returned `tokenId` is `0`
- If the offer is collection-wide, collect `assetId` before execution
- If the offer targets ERC1155, confirm the requested quantity before execution
- Do not execute against a generic order summary that is missing the original order fields
## Minimum Success Path
1. Query buy-side orders with `side=0`
2. Let the user choose one exact returned order object
3. Ask for `assetId` if the offer is collection-wide
4. Ask for `quantity` if the offer is ERC1155
5. Show preview and wait for confirmation
## Accept Offer Parameters
- `network`: target network
- `operationType`: `acceptOffer`
- `acceptOfferOrder.order`: required order object returned by query
- `acceptOfferOrder.assetId`: optional token ID, but required for collection-wide offers
- `acceptOfferOrder.quantity`: optional, default `1`
Important notes:
- Use buy-side orders only: `side=0`
- For collection-wide offers (`saleKind=7`), `assetId` is required when accepting the offer
- Do not display a collection-wide offer as token `#0`; `tokenId=0` in this case is not a real NFT selection
- For ERC1155 offers, `quantity` must not exceed the offered fillable amount
- The SDK may set NFT approval before executing the final trade transaction
- Unlike ERC20-priced `buy`, `acceptOffer` does not need `paymentTokenDecimals` because it fills a buy-side order and approves the NFT side instead of calculating ERC20 approval
## Minimal Payload Shape
```json
{
"network": "base",
"confirmed": true,
"operationType": "acceptOffer",
"acceptOfferOrder": {
"order": {
"orderId": "...",
"contractAddress": "0x...",
"schema": "ERC721",
"standard": "element-ex-v3",
"maker": "0x...",
"paymentToken": "0x...",
"price": "0.003",
"saleKind": 7,
"side": 0
},
"assetId": "22",
"quantity": "1"
}
}
```
Run with `node scripts/lib/entry.js "$INPUT"`.
FILE:references/offer.md
# Offer
Use offer to create a buy order.
## Required Before Execution
- `network` is confirmed
- NFT contract address is confirmed
- `assetSchema` is explicitly confirmed as `ERC721` or `ERC1155`
- offer price is confirmed
- `paymentToken` is resolved if the user wants a supported specific ERC20 token
## Do Not Proceed If
- the payment token is still ambiguous
- the requested ERC20 is unsupported for that chain
- `assetSchema` is still implicit or guessed
- the user wants to use a native token instead of an ERC20 payment token
- the offer is token-specific and `assetId` is still missing
- the offer targets ERC1155 and `quantity` is still missing
- confirmation has not been received
## Minimum Success Path
1. Confirm `network`, collection address, `assetSchema`, and offer price
2. Resolve `paymentToken` only if the user wants a supported specific ERC20 token from [payment-tokens.md](references/payment-tokens.md)
3. Leave `assetId` empty for collection-wide offers
4. Add `assetId` for token-specific offers
5. Add `assetSchema` and `quantity` for ERC1155
6. Show preview and wait for confirmation
## Offer Parameters
- `network`: target network
- `operationType`: `offer`
- `offerOrder.assetAddress`: required NFT contract address
- `offerOrder.paymentTokenAmount`: required base-unit amount. Convert it using the token decimals from [payment-tokens.md](references/payment-tokens.md)
- `offerOrder.paymentToken`: optional ERC20 payment token address; native tokens are not supported for offers. When omitted, the offer typically uses the chain's wrapped native ERC20 token such as WETH or WBNB
- `offerOrder.expirationTime`: optional expiration timestamp
- `offerOrder.assetId`: optional token ID
- `offerOrder.assetSchema`: required, `ERC721` or `ERC1155`
- `offerOrder.quantity`: optional, default `1`
Notes:
- For collection-wide offers, do not specify `assetId`
- For specific-token offers, specify `assetId`
- Always explicitly set `assetSchema`; do not assume `ERC721`
- For ERC1155 offers, set `assetSchema` and `quantity`
- Offer payment tokens must be ERC20 tokens; do not use the native token address for offer creation
- If the requested ERC20 is not listed as supported for that chain, do not use it for offer creation
## Minimal Payload Shapes
```json
{
"network": "base",
"confirmed": true,
"operationType": "offer",
"offerOrder": {
"assetAddress": "0x...",
"assetSchema": "ERC721",
"paymentTokenAmount": "100000000",
"paymentToken": "0x...",
"expirationTime": 1775433600
}
}
```
```json
{
"network": "base",
"confirmed": true,
"operationType": "offer",
"offerOrder": {
"assetAddress": "0x...",
"assetId": "100001",
"assetSchema": "ERC1155",
"quantity": "2",
"paymentTokenAmount": "100000000",
"expirationTime": 1775433600
}
}
```
Run with `node scripts/lib/entry.js "$INPUT"`.
FILE:references/cancel.md
# Cancel
Use cancel to cancel existing orders created by the configured wallet.
## Required Before Execution
- `network` is confirmed
- the order object came directly from query results
- the order belongs to the configured wallet
- the order has the required cancel fields
## Do Not Proceed If
- the user only provided a transaction hash
- the user only provided a wallet address
- the user only provided an order ID but the full returned order object has not been recovered yet
- the available data is a summary instead of the full returned order object
- confirmation has not been received
Recommended flow:
1. Use `Query Account Orders` to find the user's active orders
2. If needed, use `Query Orders` with a `maker` filter to find matching orders
3. Cancel using the exact returned order object
## Cancellation Recovery Path
- If the user gives an `orderId`, first recover the full order object before canceling
- If the user gives a transaction hash, explain that it is not an order ID and use account or NFT context to find the related order
- If the user gives `contractAddress + tokenId`, query the relevant account orders and match the NFT before canceling
- If the user gives only a wallet address, first query that wallet's orders on the specified chain
## Cancel Parameters
- `network`: target network
- `operationType`: `cancel`
- `ordersToCancel`: array of order objects to cancel
Required fields from the order object:
| Field | Description | Example |
|-------|-------------|---------|
| `maker` | order creator address, must match the configured wallet | `"0x..."` |
| `schema` | token standard, `ERC721` or `ERC1155` | `"ERC721"` |
| `standard` | should be `element-ex-v3` | `"element-ex-v3"` |
| `exchangeData` | complete signed order payload | `'{"hash":"...",...}'` |
Fields often present but not required by cancel:
`orderId`, `side`, `contractAddress`, `tokenId`, `price`, `paymentToken`, `saleKind`, `listingTime`, `expirationTime`, `quantity`, `priceBase`, `priceUSD`, `taker`
Important notes:
- `exchangeData` contains the nonce and signed order details actually used on-chain
- `maker` must match the configured wallet
- `standard` must be `element-ex-v3`
- `schema` controls the cancel path
- Use the exact order object returned from query; do not modify fields
- Do not substitute a transaction hash, wallet address, or order summary for the required order object
System rules for cancel:
1. Show which orders will be canceled
2. Ask for explicit confirmation
3. Show transaction hash after submission
4. If needed, show the Element collection URL after resolving slug through `element-nft-tracker`
```bash
NETWORK="base"
ORDERS='[{"orderId":"...","maker":"0x...","contractAddress":"0x...","tokenId":"1","price":"10000000000000000",...}]'
INPUT=$(jq -n \
--arg network "$NETWORK" \
--argjson orders "$ORDERS" \
'{
confirmed: true,
network: $network,
operationType: "cancel",
ordersToCancel: { orders: $orders }
}')
node scripts/lib/entry.js "$INPUT"
```
FILE:references/query-account-orders.md
# Query Account Orders
Use this when the user asks:
- "Show my orders"
- "What listings do I have?"
- "What has this wallet listed on Element?"
Ask for the required `network` first before executing this query. Do not iterate over multiple chains to find the user's orders.
This is account-specific and uses the unified `entry.ts` executor.
This queries orders for a specified account on a specified network.
If `wallet_address` is omitted, the query defaults to the account address associated with the configured API key. If `wallet_address` is provided, it can query another wallet's orders.
## Do Not Proceed If
- the payload uses `operation` instead of `operationType`
- `wallet_address`, `limit`, `cursor`, or `contract_address` are placed at the top level instead of inside `queryAccountOrders`
- `network` is missing
## Payload Rules
- Use top-level `operationType: "queryAccountOrders"`
- Use top-level `network: "base"` style network selection
- Put query-specific fields inside `queryAccountOrders`
- Do not flatten `wallet_address` or other query fields onto the top level
```json
{
"operationType": "queryAccountOrders",
"network": "base",
"queryAccountOrders": {
"wallet_address": "0x...",
"limit": 20
}
}
```
Run with `node scripts/lib/entry.js "$INPUT"`.
Returns:
- `chain`
- `usingDefaultAccount`
- `walletAddress`
- `count`
- normalized order summaries
- `orders[].expirationTime` as a readable UTC time string
Result display rules:
- If `count > 1`, do not describe the result as a single order
- When multiple orders are returned, list each order or explicitly say the output is truncated
- The displayed order count must match the actual returned `count`
FILE:scripts/entry.ts
import {
ElementSDK,
OrderQuery,
CancelOrdersParams,
MakeERC721SellOrdersParams,
MakeOrderParams,
FillOrderParams,
Network,
NULL_ADDRESS,
ETH_TOKEN_ADDRESS,
getChainId,
getChainMId,
getRpcUrlFromRemote,
BatchBuyWithETHParams,
} from "./code/index";
import { ethers } from "ethers";
import { QueryAccountOrdersParams } from "./code/src/api/openApiTypes";
const EXPLORER_URLS: Record<string, string> = {
eth: "https://etherscan.io",
bsc: "https://bscscan.com",
polygon: "https://polygonscan.com",
avalanche: "https://snowtrace.io",
arbitrum: "https://arbiscan.io",
zksync: "https://explorer.zksync.io",
linea: "https://lineascan.build",
base: "https://basescan.org",
opbnb: "https://opbnbscan.com",
scroll: "https://scrollscan.com",
manta_pacific: "https://manta.socialscan.net",
optimism: "https://optimistic.etherscan.io",
mantle: "https://mantlescan.xyz",
zkfair: "https://zkfair.io",
blast: "https://blastscan.io",
merlin: "https://merlinchain.io",
mode: "https://explorer.mode.network",
cyber: "https://cyber.socialscan.net",
bob: "https://bobscan.com",
lightlink: "https://explorer.lightlink.io",
nanon: "https://nanonscan.io",
bera: "https://berascan.com",
zeta: "https://zetachain-node.blockscout.com",
nibiru: "https://nibiscan.io",
abstract: "https://abscan.org",
monad: "https://monadscan.xyz",
bitlayer: "https://bitlayerscan.com",
mantra: "https://mantrascan.io",
};
type OperationType =
| "erc721sell"
| "erc1155sell"
| "buy"
| "offer"
| "acceptOffer"
| "query"
| "queryAccountOrders"
| "cancel"
| "getAddress";
interface InputParams {
network?: Network;
operationType: OperationType;
confirmed?: boolean;
sellOrders?: MakeERC721SellOrdersParams;
erc1155sellOrder?: MakeOrderParams;
offerOrder?: MakeOrderParams;
acceptOfferOrder?: FillOrderParams;
buyOrders?: BatchBuyWithETHParams;
queryOrders?: OrderQuery;
queryAccountOrders?: QueryAccountOrdersParams;
ordersToCancel?: CancelOrdersParams;
}
interface Credentials {
apiKey: string;
wallet: { private_key: string };
}
// ============== Utilities ==============
function log(data: object): void {
console.log(JSON.stringify(data));
}
function isBlank(value: unknown): boolean {
return value == null || (typeof value === "string" && value.trim() === "");
}
function getExplorerUrl(network: string): string {
return EXPLORER_URLS[network.toLowerCase()] || "https://etherscan.io";
}
function normalizeQuantity(quantity?: string | number): number {
const parsed = Number(quantity);
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
}
function calculateOrderCost(order: any, quantity?: string | number): string {
const orderPrice = Number(order?.price);
if (!Number.isFinite(orderPrice)) {
return String(order?.price ?? "");
}
const requestedQuantity = normalizeQuantity(quantity);
const availableQuantity = Number(order?.quantity);
if (
String(order?.schema).toUpperCase() === "ERC1155" &&
Number.isFinite(availableQuantity) &&
availableQuantity > 0
) {
return String((orderPrice * requestedQuantity) / availableQuantity);
}
return String(orderPrice * requestedQuantity);
}
function formatUnixTimestamp(
timestamp?: string | number | null,
): string | null {
if (timestamp == null || timestamp === "") return null;
const numeric = Number(timestamp);
if (!Number.isFinite(numeric) || numeric <= 0) {
return String(timestamp);
}
return new Date(numeric * 1000).toISOString().replace(".000Z", " UTC");
}
function serializeOrder(order: any) {
return {
orderId: order.orderId,
maker: order.maker,
contractAddress: order.contractAddress,
tokenId: order.tokenId,
schema: order.schema,
standard: order.standard,
quantity: order.quantity,
price: order.price,
priceBase: order.priceBase,
priceUSD: order.priceUSD,
paymentToken: order.paymentToken,
saleKind: order.saleKind,
side: order.side,
listingTime: formatUnixTimestamp(order.listingTime),
expirationTime: formatUnixTimestamp(order.expirationTime),
taker: order.taker,
exchangeData: order.exchangeData,
};
}
function isNativePaymentToken(paymentToken?: string | null): boolean {
if (isBlank(paymentToken)) return true;
const normalized = String(paymentToken).toLowerCase();
return normalized === NULL_ADDRESS || normalized === ETH_TOKEN_ADDRESS;
}
function extractErrorMessage(error: any): string {
if (error?.reason) return String(error.reason);
if (error?.message) return String(error.message);
if (error?.error?.message) return String(error.error.message);
if (typeof error === "string") return error;
return JSON.stringify(error);
}
function extractErrorCode(error: any): string | null {
if (error?.code) return String(error.code);
if (error?.error?.code) return String(error.error.code);
return null;
}
function logError(
type: string,
message: string,
code: string | null = null,
extra: object = {},
): void {
log({ status: "error", type, message, code, ...extra });
process.exit(1);
}
function validateRequiredFields(
operation: OperationType,
values: Array<{
field: string;
value: unknown;
rule?: (value: unknown) => boolean;
detail?: string;
}>,
): void {
const missing = values
.filter(({ value, rule }) => (rule ? !rule(value) : isBlank(value)))
.map(({ field, detail }) => ({ field, detail }));
if (missing.length === 0) return;
const fields = missing.map((item) => item.field);
const details = missing
.filter((item) => item.detail)
.map((item) => `item.field: item.detail`);
logError(
"validation",
`Missing or invalid required parameters for operation: fields.join(", ")`,
null,
{
operation,
fields,
details: details.length ? details : undefined,
},
);
}
function validateOrderFields(
operation: OperationType,
order: any,
prefix: string,
fields: Array<{ field: string; detail?: string }>,
): void {
validateRequiredFields(
operation,
fields.map(({ field, detail }) => ({
field: `prefix.field`,
value: order?.[field],
detail,
})),
);
}
function validateInput(input: InputParams): void {
const { operationType } = input;
const stateChangingOperations: OperationType[] = [
"erc721sell",
"erc1155sell",
"buy",
"offer",
"acceptOffer",
"cancel",
];
if (isBlank(operationType)) {
logError("validation", "operationType is required");
}
if (isBlank(input.network)) {
logError("validation", `network is required for operationType`, null, {
operation: operationType,
fields: ["network"],
});
}
if (
stateChangingOperations.includes(operationType) &&
input.confirmed !== true
) {
logError(
"validation",
`operationType requires confirmed=true after explicit user confirmation`,
null,
{
operation: operationType,
fields: ["confirmed"],
},
);
}
switch (operationType) {
case "erc721sell": {
validateRequiredFields(operationType, [
{
field: "sellOrders.items",
value: input.sellOrders?.items,
rule: (value) => Array.isArray(value) && value.length > 0,
detail: "Provide at least one ERC721 item to list",
},
]);
(input.sellOrders?.items ?? []).forEach((item, index) => {
validateRequiredFields(operationType, [
{
field: `sellOrders.items[index].erc721TokenAddress`,
value: item?.erc721TokenAddress,
},
{
field: `sellOrders.items[index].erc721TokenId`,
value: item?.erc721TokenId,
},
{
field: `sellOrders.items[index].paymentTokenAmount`,
value: item?.paymentTokenAmount,
},
]);
});
return;
}
case "erc1155sell":
validateRequiredFields(operationType, [
{
field: "erc1155sellOrder.assetAddress",
value: input.erc1155sellOrder?.assetAddress,
},
{
field: "erc1155sellOrder.assetId",
value: input.erc1155sellOrder?.assetId,
},
{
field: "erc1155sellOrder.quantity",
value: input.erc1155sellOrder?.quantity,
},
{
field: "erc1155sellOrder.paymentTokenAmount",
value: input.erc1155sellOrder?.paymentTokenAmount,
},
]);
return;
case "offer":
validateRequiredFields(operationType, [
{
field: "offerOrder.assetAddress",
value: input.offerOrder?.assetAddress,
},
{
field: "offerOrder.assetSchema",
value: input.offerOrder?.assetSchema,
detail: "Explicitly set ERC721 or ERC1155 for offer creation",
},
{
field: "offerOrder.paymentTokenAmount",
value: input.offerOrder?.paymentTokenAmount,
},
]);
return;
case "acceptOffer": {
validateRequiredFields(operationType, [
{
field: "acceptOfferOrder.order",
value: input.acceptOfferOrder?.order,
},
]);
const order = input.acceptOfferOrder?.order as any;
validateOrderFields(operationType, order, "acceptOfferOrder.order", [
{ field: "orderId" },
{ field: "contractAddress" },
{ field: "standard" },
{ field: "schema" },
{ field: "side", detail: "Use a buy-side order returned by query" },
{ field: "paymentToken" },
{ field: "price" },
]);
const saleKind = Number(order?.saleKind);
if (
(saleKind === 7 || saleKind === 8) &&
isBlank(input.acceptOfferOrder?.assetId)
) {
logError(
"validation",
"acceptOfferOrder.assetId is required for collection-wide offers",
null,
{ operation: operationType, fields: ["acceptOfferOrder.assetId"] },
);
}
return;
}
case "buy": {
validateRequiredFields(operationType, [
{
field: "buyOrders.orders",
value: input.buyOrders?.orders,
rule: (value) => Array.isArray(value) && value.length > 0,
detail: "Provide at least one order returned by query",
},
]);
const orders = input.buyOrders?.orders ?? [];
orders.forEach((order, index) => {
validateOrderFields(
operationType,
order,
`buyOrders.orders[index]`,
[
{ field: "orderId" },
{ field: "contractAddress" },
{ field: "standard" },
{ field: "schema" },
{
field: "side",
detail: "Use a sell-side order returned by query",
},
{ field: "paymentToken" },
{ field: "price" },
],
);
if (!isNativePaymentToken(order?.paymentToken)) {
validateRequiredFields(operationType, [
{
field: `buyOrders.orders[index].paymentTokenDecimals`,
value: order?.paymentTokenDecimals,
detail:
"ERC20-priced buys require paymentTokenDecimals; look it up from the payment token reference instead of guessing",
},
]);
}
});
const hasERC1155 = orders.some(
(order: any) => String(order?.schema).toUpperCase() === "ERC1155",
);
if (hasERC1155) {
validateRequiredFields(operationType, [
{
field: "buyOrders.quantities",
value: input.buyOrders?.quantities,
rule: (value) =>
Array.isArray(value) && value.length === orders.length,
detail:
"ERC1155 buys require a quantities array aligned with orders",
},
]);
}
return;
}
case "query":
validateRequiredFields(operationType, [
{
field: "queryOrders.asset_contract_address",
value: input.queryOrders?.asset_contract_address,
},
]);
return;
case "queryAccountOrders":
return;
case "cancel": {
validateRequiredFields(operationType, [
{
field: "ordersToCancel.orders",
value: input.ordersToCancel?.orders,
rule: (value) => Array.isArray(value) && value.length > 0,
detail: "Provide at least one full order object to cancel",
},
]);
(input.ordersToCancel?.orders ?? []).forEach((order, index) => {
validateOrderFields(
operationType,
order,
`ordersToCancel.orders[index]`,
[
{ field: "maker" },
{ field: "schema" },
{ field: "standard" },
{ field: "exchangeData" },
],
);
});
return;
}
case "getAddress":
return;
default:
return;
}
}
// ============== Credentials & SDK ==============
async function getCredentials(): Promise<Credentials> {
const apiKeyFromEnv = process.env.ELEMENT_API_KEY;
const privateKeyFromEnv = process.env.ELEMENT_WALLET_PRIVATE_KEY;
if (!apiKeyFromEnv || !privateKeyFromEnv) {
throw new Error(
"Missing required environment variables: ELEMENT_API_KEY and ELEMENT_WALLET_PRIVATE_KEY",
);
}
return {
apiKey: apiKeyFromEnv,
wallet: { private_key: privateKeyFromEnv },
};
}
async function createSDK(network: Network): Promise<ElementSDK> {
const credentials = await getCredentials();
const chainId = getChainId(network, false);
const chainMId = getChainMId(chainId);
const rpcUrl = await getRpcUrlFromRemote(chainMId);
const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
const signer = new ethers.Wallet(credentials.wallet.private_key, provider);
return new ElementSDK({
networkName: network,
isTestnet: false,
apiKey: credentials.apiKey,
signer: signer,
});
}
async function getInput(): Promise<InputParams> {
if (process.argv[2]) {
try {
return JSON.parse(process.argv[2]);
} catch (e) {
throw new Error(
`Invalid JSON in command argument: extractErrorMessage(e)`,
);
}
}
return new Promise((resolve, reject) => {
let data = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
data += chunk;
});
process.stdin.on("end", () => {
try {
resolve(JSON.parse(data.trim()));
} catch (e) {
reject(new Error(`Invalid JSON in stdin: extractErrorMessage(e)`));
}
});
process.stdin.on("error", (e) =>
reject(new Error(`stdin error: extractErrorMessage(e)`)),
);
});
}
// ============== Operation Handlers ==============
async function handleERC721Sell(
sdk: ElementSDK,
params: MakeERC721SellOrdersParams,
) {
if (!params) throw new Error("sellOrders is not set");
const result = await sdk.makeERC721SellOrders(params);
if (result.succeedList.length === 0 && result.failedList.length > 0) {
logError("erc721sell", "All orders failed", null, {
failedList: result.failedList.map((item: any) => ({
tokenId: item.assetTokenId,
contractAddress: item.assetContract,
error: item.errorDetail,
})),
});
}
log({
status: "success",
operation: "erc721sell",
succeedCount: result.succeedList.length,
failedCount: result.failedList.length,
succeedList: result.succeedList.map((o: any) => ({
orderId: o.orderId,
contractAddress: o.contractAddress,
tokenId: o.tokenId,
price: o.price,
paymentToken: o.paymentToken,
expirationTime: formatUnixTimestamp(o.expirationTime),
})),
failedList: result.failedList.map((item: any) => ({
tokenId: item.assetTokenId,
contractAddress: item.assetContract,
error: item.errorDetail,
})),
});
}
async function handleERC1155Sell(sdk: ElementSDK, params: MakeOrderParams) {
if (!params) throw new Error("erc1155sellOrder is not set");
const result = await sdk.makeSellOrder(params);
log({
status: "success",
operation: "erc1155sell",
orderId: result.orderId,
contractAddress: result.contractAddress,
tokenId: result.tokenId,
price: result.price,
paymentToken: result.paymentToken,
listingTime: formatUnixTimestamp(result.listingTime),
expirationTime: formatUnixTimestamp(result.expirationTime),
});
}
async function handleBuy(
sdk: ElementSDK,
params: BatchBuyWithETHParams,
explorerBase: string,
) {
if (!params) throw new Error("buyOrders is not set");
const orders = params.orders ?? [];
const hasERC20Payment = orders.some(
(order: any) => !isNativePaymentToken(order?.paymentToken),
);
if (hasERC20Payment) {
if (orders.length !== 1) {
logError(
"buy",
"ERC20-priced buys currently support exactly one order at a time",
null,
{
orderCount: orders.length,
paymentTokens: orders.map(
(order: any) => order?.paymentToken ?? null,
),
},
);
}
const order = orders[0] as any;
const quantity = params.quantities?.[0];
const tx = await sdk.fillOrder({
order,
quantity,
});
let receipt;
try {
receipt = await tx.wait();
} catch (e) {
logError(
"buy",
`Transaction failed on-chain: extractErrorMessage(e)`,
extractErrorCode(e),
{
transactionHash: tx.hash,
explorerUrl: `explorerBase/tx/tx.hash`,
},
);
}
log({
status: receipt.status === 1 ? "success" : "failed",
operation: "buy",
paymentMode: "erc20-single-fill",
orders: [
{
orderId: order.orderId,
contractAddress: order.contractAddress,
tokenId: order.tokenId,
schema: order.schema,
requestedQuantity: String(quantity ?? "1"),
paymentToken: order.paymentToken,
cost: calculateOrderCost(order, quantity),
},
],
transactionHash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
explorerUrl: `explorerBase/tx/tx.hash`,
});
return;
}
const tx = await sdk.batchBuyWithETH(params);
let receipt;
try {
receipt = await tx.wait();
} catch (e) {
logError(
"buy",
`Transaction failed on-chain: extractErrorMessage(e)`,
extractErrorCode(e),
{
transactionHash: tx.hash,
explorerUrl: `explorerBase/tx/tx.hash`,
},
);
}
log({
status: receipt.status === 1 ? "success" : "failed",
operation: "buy",
paymentMode: "native-batch-buy",
orders: params.orders.map((order: any, index: number) => ({
orderId: order.orderId,
contractAddress: order.contractAddress,
tokenId: order.tokenId,
schema: order.schema,
requestedQuantity: String(params.quantities?.[index] ?? "1"),
paymentToken: order.paymentToken,
cost: calculateOrderCost(order, params.quantities?.[index]),
})),
transactionHash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
async function handleOffer(sdk: ElementSDK, params: MakeOrderParams) {
if (!params) throw new Error("offerOrder is not set");
const result = await sdk.makeBuyOrder(params);
log({
status: "success",
operation: "offer",
orderId: result.orderId,
contractAddress: result.contractAddress,
price: result.price,
paymentToken: result.paymentToken,
listingTime: formatUnixTimestamp(result.listingTime),
expirationTime: formatUnixTimestamp(result.expirationTime),
});
}
async function handleAcceptOffer(
sdk: ElementSDK,
params: FillOrderParams,
explorerBase: string,
) {
if (!params?.order) throw new Error("acceptOfferOrder.order is not set");
const tx = await sdk.fillOrder(params);
let receipt;
try {
receipt = await tx.wait();
} catch (e) {
logError(
"acceptOffer",
`Transaction failed on-chain: extractErrorMessage(e)`,
extractErrorCode(e),
{
transactionHash: tx.hash,
explorerUrl: `explorerBase/tx/tx.hash`,
},
);
}
log({
status: receipt.status === 1 ? "success" : "failed",
operation: "acceptOffer",
acceptedOffer: {
orderId: params.order.orderId,
maker: params.order.maker,
contractAddress: params.order.contractAddress,
tokenId: String(params.assetId ?? params.order.tokenId ?? ""),
schema: params.order.schema,
quantity: String(params.quantity ?? "1"),
paymentToken: params.order.paymentToken,
price: params.order.price,
proceeds: calculateOrderCost(params.order, params.quantity),
},
transactionHash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
async function handleQuery(sdk: ElementSDK, query: OrderQuery) {
if (!query?.asset_contract_address) {
throw new Error("asset_contract_address is not set");
}
const orders = await sdk.queryOrders(query);
log({
status: "success",
operation: "query",
count: orders.length,
orders: orders.map((o: any) => serializeOrder(o)),
});
}
async function handleQueryAccountOrders(
sdk: ElementSDK,
params: QueryAccountOrdersParams = {},
) {
const payload = await sdk.queryAccountOrders(params);
const assetList = payload?.assetList ?? [];
const chain = (sdk.apiOption?.chain || "").toString();
log({
status: "success",
operation: "queryAccountOrders",
chain,
usingDefaultAccount: isBlank(params.wallet_address),
walletAddress: params.wallet_address ?? null,
contractAddress: params.contract_address ?? null,
cursor: params.cursor ?? null,
pageInfo: payload?.pageInfo ?? null,
count: assetList.length,
orders: assetList.map((item: any) => ({
cursor: item?.cursor ?? null,
name: item?.asset?.name,
slug: item?.asset?.collection?.slug,
tokenId: item?.asset?.tokenId,
collection: item?.asset?.collection?.name,
contractAddress: item?.asset?.contractAddress,
price: item?.orderData?.accountOrder?.price,
priceUSD: item?.orderData?.accountOrder?.priceUSD,
paymentToken: item?.orderData?.accountOrder?.paymentToken,
quantity: item?.orderData?.accountOrder?.quantity,
side: item?.orderData?.accountOrder?.side,
saleKind: item?.orderData?.accountOrder?.saleKind,
standard: item?.orderData?.accountOrder?.standard,
schema: item?.orderData?.accountOrder?.schema,
listingTime: formatUnixTimestamp(
item?.orderData?.accountOrder?.listingTime,
),
expirationTime: formatUnixTimestamp(
item?.orderData?.accountOrder?.expirationTime,
),
})),
});
}
async function handleGetAddress(sdk: ElementSDK): Promise<void> {
const address = await sdk.web3Signer.getCurrentAccount();
log({
status: "success",
operation: "getAddress",
address,
});
}
async function handleCancel(
sdk: ElementSDK,
params: CancelOrdersParams,
explorerBase: string,
) {
if (!params?.orders?.length)
throw new Error("ordersToCancel is not set or empty");
const result = await sdk.cancelOrders({ orders: params.orders });
if (result.succeedTransactions.length === 0) {
logError("cancel", "No orders were successfully cancelled");
}
const transactions = [];
for (const txInfo of result.succeedTransactions) {
let receipt;
try {
receipt = await txInfo.transaction.wait();
} catch (e) {
transactions.push({
transactionHash: txInfo.transaction.hash,
status: "failed",
message: extractErrorMessage(e),
explorerUrl: `explorerBase/tx/txInfo.transaction.hash`,
});
continue;
}
transactions.push({
transactionHash: txInfo.transaction.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
status: receipt.status === 1 ? "success" : "failed",
explorerUrl: `explorerBase/tx/txInfo.transaction.hash`,
});
}
log({
status: "success",
operation: "cancel",
cancelledCount: result.succeedTransactions.length,
transactions,
});
}
// ============== Main ==============
async function main() {
let input: InputParams;
try {
input = await getInput();
} catch (e) {
logError("input", extractErrorMessage(e), extractErrorCode(e));
}
validateInput(input);
const { network, operationType } = input;
let sdk: ElementSDK | undefined;
const needsSdk = true;
if (needsSdk) {
try {
sdk = await createSDK(network!);
} catch (e) {
logError("sdk_init", extractErrorMessage(e), extractErrorCode(e));
}
}
const explorerBase = network
? getExplorerUrl(network)
: "https://etherscan.io";
try {
switch (operationType) {
case "erc721sell":
await handleERC721Sell(sdk!, input.sellOrders!);
break;
case "erc1155sell":
await handleERC1155Sell(sdk!, input.erc1155sellOrder!);
break;
case "buy":
await handleBuy(sdk!, input.buyOrders!, explorerBase);
break;
case "offer":
await handleOffer(sdk!, input.offerOrder!);
break;
case "acceptOffer":
await handleAcceptOffer(sdk!, input.acceptOfferOrder!, explorerBase);
break;
case "query":
await handleQuery(sdk!, input.queryOrders!);
break;
case "queryAccountOrders":
await handleQueryAccountOrders(sdk!, input.queryAccountOrders);
break;
case "cancel":
await handleCancel(sdk!, input.ordersToCancel!, explorerBase);
break;
case "getAddress":
await handleGetAddress(sdk!);
break;
default:
throw new Error(`Unsupported operation type: operationType`);
}
} catch (e) {
logError(
operationType || "unknown",
extractErrorMessage(e),
extractErrorCode(e),
);
}
}
main();
FILE:scripts/code/index.ts
export { ElementSDK } from './src/index'
export { ethers, providers, Signer, BigNumber } from 'ethers'
export type { TransactionResponse, TransactionReceipt } from '@ethersproject/abstract-provider'
export type {
OrderQuery
} from './src/api/openApiTypes'
export {
NULL_ADDRESS,
ETH_TOKEN_ADDRESS,
Network,
OrderSide,
SaleKind,
Standard,
Market
} from './src/types/types'
export type {
SignerOrProvider,
Asset,
ElementAPIConfig,
OrderInformation,
Order,
GasParams,
ERC721SellOrderItem,
MakeERC721SellOrdersParams,
FailedERC721Item,
MakeERC721SellOrdersResponse,
MakeOrderParams,
FillOrderParams,
BatchBuyWithETHParams,
EncodeTradeDataParams,
CancelOrderParams,
CancelOrdersParams,
CancelOrdersResponse,
CancelAllOrdersByMakerParams
} from './src/types/types'
export { getChain, getChainId, getChainMId } from './src/util/chainUtil'
export { getRpcUrlFromRemote } from './src/contracts/config'
FILE:scripts/code/src/signer/Web3Signer.ts
import { ethers, Signer } from 'ethers'
import { TransactionRequest, TransactionResponse } from '@ethersproject/abstract-provider'
import { ContractABI } from '../contracts/abi'
import { GasParams, NULL_ADDRESS, SignerOrProvider } from '../types/types'
import { _TypedDataEncoder } from 'ethers/lib/utils'
import { estimateGas } from '../util/gasUtil'
export interface LimitedCallSpec extends GasParams {
from: string;
to: string;
data: string;
value?: string;
}
const erc20Contract = new ethers.Contract(NULL_ADDRESS, ContractABI.erc20.abi)
const erc721Contract = new ethers.Contract(NULL_ADDRESS, ContractABI.erc721.abi)
const erc1155Contract = new ethers.Contract(NULL_ADDRESS, ContractABI.erc1155.abi)
export class Web3Signer {
public chainId: number
public signer: SignerOrProvider
constructor(signer: SignerOrProvider, chainId: number) {
if (signer instanceof Signer) {
if (!signer.provider) {
throw Error('signer.provider is unset')
}
}
this.signer = signer
this.chainId = chainId
}
public static getOrderHash(typedData: any): string {
return _TypedDataEncoder.hash(typedData.domain, typedData.types, typedData.message)
}
public async signTypedData(account: string, typedData: any): Promise<any> {
const signer = await this.getSigner(account)
const typedDataSigner = signer as any
if (typedDataSigner._signTypedData) {
const typeSignStr = await typedDataSigner._signTypedData(typedData.domain, typedData.types, typedData.message)
const signer = ethers.utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, typeSignStr)
if (account.toLowerCase() !== signer.toLowerCase()) {
throw Error(`signTypedData failed, account : account, signer = signer`)
}
return ethers.utils.splitSignature(typeSignStr)
} else {
throw Error('Unsupported signTypedData')
}
}
public async ethSend(call: LimitedCallSpec): Promise<TransactionResponse> {
const transactionRequest: TransactionRequest = {
from: call.from,
to: call.to,
data: call.data
}
if (call.value && ethers.BigNumber.from(call.value).gt(0)) {
transactionRequest.value = ethers.BigNumber.from(call.value)
}
const signer = await this.getSigner(call.from)
if (call.maxFeePerGas && call.maxPriorityFeePerGas) {
transactionRequest.maxFeePerGas = ethers.BigNumber.from(call.maxFeePerGas)
transactionRequest.maxPriorityFeePerGas = ethers.BigNumber.from(call.maxPriorityFeePerGas)
} else if (call.gasPrice) {
transactionRequest.gasPrice = ethers.BigNumber.from(call.gasPrice)
} else {
if (!(this.signer instanceof ethers.providers.Web3Provider)) {
const gas = await estimateGas(this.chainId)
if (gas) {
transactionRequest.maxFeePerGas = gas.maxFeePerGas
transactionRequest.maxPriorityFeePerGas = gas.maxPriorityFeePerGas
}
}
}
// Use provided gas limit if specified, otherwise let provider estimate
if (call.gas) {
transactionRequest.gasLimit = ethers.BigNumber.from(call.gas)
}
return await signer.sendTransaction(transactionRequest)
}
public async getSigner(account?: string): Promise<Signer> {
let signer
if (this.signer instanceof ethers.providers.Web3Provider) {
let accounts = await this.signer.listAccounts()
if (!accounts?.length) {
accounts = await this.signer.send('eth_requestAccounts', [])
if (!accounts?.length) {
throw Error(`getSigner failed, accounts:accounts`)
}
}
if (account) {
if (!accounts.find(item => item.toString().toLowerCase() === account.toLowerCase())) {
throw Error(`Account mismatch, account:account.toLowerCase(), but connected accounts:accounts`)
}
signer = this.signer.getSigner(account)
} else {
signer = this.signer.getSigner(accounts[0])
}
if (this.signer.provider?.isMetaMask && this.signer.provider?.request) {
const chainId = await signer.getChainId()
if (chainId != this.chainId) {
await this.signer.provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x' + Number(this.chainId).toString(16) }]
})
} else {
return signer
}
}
} else {
signer = this.signer
const signerAddress = await signer.getAddress()
if (account) {
if (account.toLowerCase() !== signerAddress.toLowerCase()) {
throw Error(`Account mismatch, account: account.toLowerCase(), but signer: signerAddress.toLowerCase()`)
}
}
}
// const chainId = await signer.getChainId()
// if (chainId != this.chainId) {
// throw Error(`chainId mismatch, chainId: chainId, but expected chainId: this.chainId`)
// }
return signer
}
public async getCurrentAccount(): Promise<string> {
let signer
if (this.signer instanceof ethers.providers.Web3Provider) {
let accounts = await this.signer.listAccounts()
if (accounts?.length) {
return accounts[0].toLowerCase()
}
accounts = await this.signer.send('eth_requestAccounts', [])
if (accounts?.length) {
return accounts[0].toLowerCase()
}
throw Error('getCurrentAccount failed, please connect web3, and choose a account.')
} else {
signer = this.signer
const account = await signer.getAddress()
return account.toLowerCase()
}
}
public async approveERC20Proxy(account: string, erc20Address: string, spender: string, gasParams?: GasParams, allowance?: string): Promise<TransactionResponse> {
const amount = allowance || ethers.constants.MaxInt256.toString()
const transaction = await erc20Contract.populateTransaction.approve(spender, amount)
if (transaction.data) {
return this.ethSend({
from: account,
to: erc20Address,
data: transaction.data,
gasPrice: gasParams?.gasPrice,
maxFeePerGas: gasParams?.maxFeePerGas,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas
})
}
throw Error(`approveERC20Proxy failed, account=account, erc20Address =erc20Address, spender=spender.`)
}
public async approveERC721Proxy(account: string, erc721Address: string, operator: string, gasParams?: GasParams, approved = true): Promise<TransactionResponse> {
const transaction = await erc721Contract.populateTransaction.setApprovalForAll(operator, approved)
if (transaction.data) {
return this.ethSend({
from: account,
to: erc721Address,
data: transaction.data,
gasPrice: gasParams?.gasPrice,
maxFeePerGas: gasParams?.maxFeePerGas,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas
})
}
throw Error(`approveERC721Proxy failed, account=account, erc721Address =erc721Address, operator=operator.`)
}
public async approveERC1155Proxy(account: string, erc1155Address: string, operator: string, gasParams: GasParams, approved = true): Promise<TransactionResponse> {
const transaction = await erc1155Contract.populateTransaction.setApprovalForAll(operator, approved)
if (transaction.data) {
return this.ethSend({
from: account,
to: erc1155Address,
data: transaction.data,
gasPrice: gasParams?.gasPrice,
maxFeePerGas: gasParams?.maxFeePerGas,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas
})
}
throw Error(`approveERC1155Proxy failed, account=account, erc1155Address =erc1155Address, operator=operator.`)
}
}
FILE:scripts/code/src/types/types.ts
import { ethers, Signer } from 'ethers'
import { TransactionResponse } from '@ethersproject/abstract-provider'
export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'
export const ETH_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
export type SignerOrProvider = Signer | ethers.providers.Web3Provider;
export enum Network {
ETH = 'eth',
BSC = 'bsc',
Polygon = 'polygon',
Avalanche = 'avalanche',
Arbitrum = 'arbitrum',
ZkSync = 'zksync',
Linea = 'linea',
Base = 'base',
OpBNB = 'opbnb',
Scroll = 'scroll',
MantaPacific = 'manta_pacific',
Optimism = 'optimism',
Mantle = 'mantle',
ZKFair = 'zkfair',
Blast = 'blast',
Merlin = 'merlin',
Mode = 'mode',
Cyber = 'cyber',
BOB = 'bob',
Lightlink = 'lightlink',
Nanon = 'nanon',
Bera = 'bera',
Zeta = 'zeta',
Nibiru = 'nibiru',
Abstract = 'abstract',
Monad = 'monad',
Bitlayer = 'bitlayer',
Mantra = 'mantra',
}
export enum OrderSide {
BuyOrder = 0,
SellOrder = 1
}
export enum SaleKind {
FixedPrice = 0,
BatchSignedERC721Order = 3,
ContractOffer = 7,
BatchOfferERC721s = 8,
}
export enum Standard {
ElementEx = 'element-ex-v3',
}
export enum Market {
ElementEx = 'element',
}
export enum AssetSchema {
ERC721 = 'ERC721',
ERC1155 = 'ERC1155'
}
export interface Asset {
assetId: string;
assetAddress: string;
assetSchema: AssetSchema;
quantity: string;
}
export interface ElementAPIConfig {
networkName: Network;
apiKey: string;
signer: SignerOrProvider;
isTestnet?: boolean;
}
export interface OrderInformation {
// Asset contract address.
contractAddress: string;
// Asset token id
tokenId: string;
// Asset schema
schema: AssetSchema | string;
// The order trading Standards.
standard: Standard | string;
// The order maker's wallet address.
maker: string;
// Listing time.
listingTime: number | string;
// Expiration time.
expirationTime: number | string;
// Priced in paymentToken, and the unit is ether.
price: number | string;
// The contract address of the paymentToken.
paymentToken: string;
// Optional payment token decimals supplied by the caller.
paymentTokenDecimals?: number | string;
// Kind of sell order. 0 for fixed-price sales, and 3 for batchSignedERC721 sell order.
saleKind: SaleKind | number | string;
// Side of the order. 0 for buy order, and 1 for sell order.
side: OrderSide | number | string;
// Order id.
orderId: string;
}
export interface Order extends OrderInformation {
// The asset quantity of order.
quantity: string;
// Priced in the native token(e.g. ETH), and the unit is ether.
priceBase: number;
// Priced in USD.
priceUSD: number;
// The order taker's wallet address
taker: string;
// Additional information
exchangeData: string;
}
export interface GasParams {
gas?: string | number;
gasPrice?: string | number;
maxFeePerGas?: string | number;
maxPriorityFeePerGas?: string | number;
}
export interface ERC721SellOrderItem {
erc721TokenId: string | number;
erc721TokenAddress: string;
paymentTokenAmount: string | number;
}
export interface MakeERC721SellOrdersParams extends GasParams {
listingTime?: number;
expirationTime?: number;
paymentToken?: string;
items: Array<ERC721SellOrderItem>
}
export interface FailedERC721Item {
assetTokenId: string;
assetContract: string;
errorDetail: string;
}
export interface MakeERC721SellOrdersResponse {
succeedList: Array<OrderInformation>;
failedList: Array<FailedERC721Item>;
}
export interface MakeOrderParams extends GasParams {
takerAddress?: string;
assetId?: string | number;
assetAddress: string;
assetSchema?: AssetSchema | string;
quantity?: string | number;
paymentToken?: string;
paymentTokenAmount: string | number;
listingTime?: number;
expirationTime?: number;
}
export interface FillOrderParams extends GasParams {
order: OrderInformation;
quantity?: string | number;
assetId?: string | number;
}
export interface BatchBuyWithETHParams extends GasParams {
orders: Array<OrderInformation>;
quantities?: Array<string | number>;
}
export interface EncodeTradeDataParams {
orders: Array<OrderInformation>;
quantities?: Array<string | number>;
tokenIds?: Array<string | number>;
taker?: string;
}
export interface TradeData {
toContract: string;
payableValue: string;
data: string;
flags: Array<boolean>;
}
export interface CancelOrderParams extends GasParams {
order: Order;
}
export interface CancelOrdersParams extends GasParams {
orders: Array<Order>;
}
export interface CancelOrdersTransaction {
orders: Array<Order>;
transaction: TransactionResponse;
}
export interface CancelOrdersResponse {
succeedTransactions: Array<CancelOrdersTransaction>;
}
export interface CancelAllOrdersByMakerParams extends GasParams {
standard?: Standard;
}
FILE:scripts/code/src/util/numberUtil.ts
import { BigNumber } from 'ethers'
export function toString(val: any): string {
if (val != null) {
if (typeof (val) == 'number') {
return BigNumber.from('0x' + val.toString(16)).toString()
}
return BigNumber.from(val).toString()
}
return ''
}
export function toNumber(val: any): number | undefined {
return val != null ? Number(val.toString()) : undefined
}
export function toHexValue(value: string) {
const hex = BigNumber.from(value).toHexString()
if (hex.startsWith('0x0') && hex.length > 3) {
return '0x' + hex.substring(3)
}
return hex
}
FILE:scripts/code/src/util/gasUtil.ts
import axios from "axios";
export async function estimateGas(chainId: number) {
if (chainId == 137) {
return estimateGasPolygon();
}
}
async function estimateGasPolygon() {
try {
const response = await axios({
method: "get",
url: "https://gasstation.polygon.technology/v2",
timeout: 5000,
});
const obj = await response.data;
const fastMaxPriorityFee = Number.parseFloat(obj.fast.maxPriorityFee);
const baseFee = Number.parseFloat(obj.estimatedBaseFee);
let maxPriorityFee = Math.floor(fastMaxPriorityFee * 1e9);
let estimatedBaseFee;
if (baseFee >= 10) {
estimatedBaseFee = Math.floor(baseFee * 1.125 * 1e9);
} else if (baseFee >= 5) {
estimatedBaseFee = Math.floor(baseFee * 1.5 * 1e9);
} else {
estimatedBaseFee = Math.floor(baseFee * 2 * 1e9);
}
return {
maxFeePerGas: maxPriorityFee + estimatedBaseFee,
maxPriorityFeePerGas: maxPriorityFee,
};
} catch (e) {}
}
FILE:scripts/code/src/util/bitsUtil.ts
import { BigNumber } from 'ethers'
export function encodeBits(args: any[][]): string {
let data = '0x'
for (const arg of args) {
data += toHexBytes(BigNumber.from(arg[0].toString()).toHexString(), arg[1])
}
return data
}
function toHexBytes(hexStr: string, bitCount: number) {
const count = bitCount / 4
const str = hexStr.toLowerCase().startsWith('0x') ? hexStr.substring(2).toLowerCase() : hexStr.toLowerCase()
if (str.length > count) {
return str.substring(str.length - count)
}
let zero = ''
for (let i = str.length; i < count; i++) {
zero += '0'
}
return zero + str
}
FILE:scripts/code/src/util/tokenUtil.ts
import { ETH_TOKEN_ADDRESS, NULL_ADDRESS } from '../types/types'
export function toContractERC20Token(erc20Token?: string) {
if (erc20Token && erc20Token.toLowerCase() != NULL_ADDRESS) {
return erc20Token.toLowerCase()
}
return ETH_TOKEN_ADDRESS
}
export function toStandardERC20Token(erc20Token?: string) {
if (erc20Token && erc20Token.toLowerCase() != ETH_TOKEN_ADDRESS) {
return erc20Token.toLowerCase()
}
return NULL_ADDRESS
}
FILE:scripts/code/src/util/receiptUtil.ts
import { TransactionReceipt } from '@ethersproject/abstract-provider'
import { Asset, AssetSchema } from '../types/types'
import { BigNumber } from 'ethers'
const BYTE32_0 = '0x0000000000000000000000000000000000000000000000000000000000000000'
const topicTransfer = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
const topicTransferSingle = '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62'
export function getBoughtAssets(receipt: TransactionReceipt): Array<Asset> {
if (!receipt.from || !receipt.logs) {
return []
}
const list: Asset[] = []
const from = receipt.from.toLowerCase()
for (const log of receipt.logs) {
if (
log.topics?.length == 4 &&
log.topics[0].toLowerCase() == topicTransfer &&
log.topics[1].toLowerCase() != BYTE32_0 &&
BigNumber.from(log.topics[2].toLowerCase()).eq(from)
) {
list.push({
assetId: BigNumber.from(log.topics[3]).toString(),
assetAddress: log.address.toLowerCase(),
assetSchema: AssetSchema.ERC721,
quantity: '1'
})
continue
}
if (
log.topics?.length == 4 &&
log.data?.length == 130 &&
log.topics[0].toLowerCase() == topicTransferSingle &&
log.topics[2].toLowerCase() != BYTE32_0 &&
BigNumber.from(log.topics[3].toLowerCase()).eq(from)
) {
list.push({
assetId: BigNumber.from(log.data.substring(0, 66)).toString(),
assetAddress: log.address.toLowerCase(),
assetSchema: AssetSchema.ERC1155,
quantity: BigNumber.from('0x' + log.data.substring(66)).toString()
})
}
}
return list
}
FILE:scripts/code/src/util/chainUtil.ts
import { Network } from '../types/types'
const CHAIN_NAMES: { [key: number]: string } = {
1: Network.ETH,
11155111: Network.ETH,
56: Network.BSC,
97: Network.BSC,
137: Network.Polygon,
43114: Network.Avalanche,
42161: Network.Arbitrum,
324: Network.ZkSync,
59144: Network.Linea,
8453: Network.Base,
204: Network.OpBNB,
534352: Network.Scroll,
169: Network.MantaPacific,
10: Network.Optimism,
5000: Network.Mantle,
42766: Network.ZKFair,
81457: Network.Blast,
4200: Network.Merlin,
34443: Network.Mode,
7560: Network.Cyber,
60808: Network.BOB,
1890: Network.Lightlink,
2748: Network.Nanon,
80094: Network.Bera,
7000: Network.Zeta,
6900: Network.Nibiru,
2741: Network.Abstract,
143: Network.Monad,
200901: Network.Bitlayer,
5888: Network.Mantra,
}
// Element 平台全局唯一 ChainMId 映射 (chainId -> chainMId)
const CHAIN_MID_MAP: { [key: number]: number } = {
1: 1, // Ethereum Mainnet
137: 101, // Polygon Mainnet
56: 201, // BSC Mainnet
43114: 401, // Avalanche Mainnet
42161: 601, // Arbitrum Mainnet
324: 701, // zkSync Era Mainnet
204: 1101, // opBNB Mainnet
8453: 1201, // Base Mainnet
534352: 1301, // Scroll Mainnet
169: 1401, // Manta Pacific
10: 1501, // Optimism Mainnet
5000: 1601, // Mantle Mainnet
42766: 1701, // ZKFair Mainnet
81457: 1801, // Blast Mainnet
4200: 1901, // Merlin Mainnet
34443: 2001, // Mode Mainnet
7560: 2101, // Cyber Mainnet
60808: 2201, // BOB Mainnet
1890: 2301, // Lightlink Mainnet
2748: 2501, // Nanon Mainnet
80094: 2601, // BeraChain Mainnet
7000: 2701, // ZetaChain Mainnet
6900: 2801, // Nibiru Mainnet
2741: 2901, // Abstract Mainnet
143: 3001, // Monad Mainnet
200901: 3101, // Bitlayer Mainnet
5888: 3201, // Mantra Mainnet
}
export function getChain(chainId: number): string {
if (CHAIN_NAMES[chainId]) {
return CHAIN_NAMES[chainId]
}
throw Error('getChain, unsupported chainId : ' + chainId)
}
/**
* 根据 chainId 获取 Element 平台的 chainMId
* @param chainId 区块链原生 chainId
* @returns Element 平台全局唯一 chainMId
*/
export function getChainMId(chainId: number): number {
if (CHAIN_MID_MAP[chainId]) {
return CHAIN_MID_MAP[chainId]
}
throw Error('getChainMId, unsupported chainId : ' + chainId)
}
export function getChainId(chain: any, isTestnet = false): number {
if (isTestnet) {
switch (chain.toString()) {
case Network.ETH:
return 11155111
case Network.BSC:
return 97
}
throw Error('getChainId, unsupported chain : ' + chain)
} else {
switch (chain.toString()) {
case Network.ETH:
return 1
case Network.BSC:
return 56
case Network.Polygon:
return 137
case Network.Avalanche:
return 43114
case Network.Arbitrum:
return 42161
case Network.ZkSync:
return 324
case Network.Linea:
return 59144
case Network.Base:
return 8453
case Network.OpBNB:
return 204
case Network.Scroll:
return 534352
case Network.MantaPacific:
return 169
case Network.Optimism:
return 10
case Network.Mantle:
return 5000
case Network.ZKFair:
return 42766
case Network.Blast:
return 81457
case Network.Merlin:
return 4200
case Network.Mode:
return 34443
case Network.Cyber:
return 7560
case Network.BOB:
return 60808
case Network.Lightlink:
return 1890
case Network.Nanon:
return 2748
case Network.Bera:
return 80094
case Network.Zeta:
return 7000
case Network.Nibiru:
return 6900
case Network.Abstract:
return 2741
case Network.Monad:
return 143
case Network.Bitlayer:
return 200901
case Network.Mantra:
return 5888
}
throw Error('getChainId, unsupported chain : ' + chain)
}
}
FILE:scripts/code/src/util/assetUtil.ts
import { Web3Signer } from '../signer/Web3Signer'
import { BigNumber, Contract } from 'ethers'
import { ContractABI, CONTRACTS_ADDRESSES } from '../contracts/config'
import { GasParams } from '../types/types'
export async function erc20Decimals(web3Signer: Web3Signer, tokenAddress: string) {
const signer = await web3Signer.getSigner()
const contract = new Contract(tokenAddress, ContractABI.erc20.abi, signer)
return await contract.decimals()
}
export async function approveERC20(
web3Signer: Web3Signer,
tokenAddress: string,
value: BigNumber,
gasParams?: GasParams
) {
if (value.eq(0)) {
return
}
const chainId = web3Signer.chainId
const signer = await web3Signer.getSigner()
const owner = await signer.getAddress()
const elementEx = CONTRACTS_ADDRESSES[chainId].ElementEx
const contract = new Contract(tokenAddress, ContractABI.erc20.abi, signer)
const allowance = await contract.allowance(owner, elementEx)
if (allowance.lt(value)) {
const tx = await web3Signer.approveERC20Proxy(owner, tokenAddress, elementEx, gasParams)
await tx.wait()
}
}
export async function setApproveForAll(
web3Signer: Web3Signer,
tokenAddress: string,
gasParams?: GasParams
) {
const chainId = web3Signer.chainId
const signer = await web3Signer.getSigner()
const owner = await signer.getAddress()
const elementEx = CONTRACTS_ADDRESSES[chainId].ElementEx
const contract = new Contract(tokenAddress, ContractABI.erc721.abi, signer)
const approved = await contract.isApprovedForAll(owner, elementEx)
if (!approved) {
const tx = await web3Signer.approveERC721Proxy(owner, tokenAddress, elementEx, gasParams)
await tx.wait()
}
}
export async function transferERC721(
web3Signer: Web3Signer,
tokenAddress: string,
tokenId: string,
toAddress: string,
gasParams?: GasParams
) {
const signer = await web3Signer.getSigner()
const contract = new Contract(tokenAddress, ContractABI.erc721.abi, signer)
const fromAddress = await signer.getAddress()
// Check if contract supports safeTransferFrom
const safeTransferFragment = contract.interface.getFunction('safeTransferFrom')
if (!safeTransferFragment) {
throw new Error('Contract does not support safeTransferFrom')
}
// Use safeTransferFrom(address from, address to, uint256 tokenId)
const tx = await contract.safeTransferFrom(fromAddress, toAddress, tokenId, gasParams || {})
return await tx.wait()
}
export async function transferERC1155(
web3Signer: Web3Signer,
tokenAddress: string,
tokenId: string,
toAddress: string,
quantity: string,
gasParams?: GasParams
) {
const signer = await web3Signer.getSigner()
const fromAddress = await signer.getAddress()
// Check if contract supports safeTransferFrom
const contract = new Contract(tokenAddress, ContractABI.erc1155.abi, signer)
const safeTransferFragment = contract.interface.getFunction('safeTransferFrom')
if (!safeTransferFragment) {
throw new Error('Contract does not support safeTransferFrom')
}
// Use safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data)
const tx = await contract.safeTransferFrom(fromAddress, toAddress, tokenId, quantity, '0x', gasParams || {})
return await tx.wait()
}
FILE:scripts/code/src/contracts/contracts.ts
import { ContractABI, CONTRACTS_ADDRESSES } from './config'
import { Contract, Signer } from 'ethers'
export { ContractABI } from './abi/index'
export function getElementExContract(chainId: number, signer: Signer): Contract {
const address = CONTRACTS_ADDRESSES[chainId as keyof typeof CONTRACTS_ADDRESSES].ElementEx
return new Contract(address, ContractABI.elementEx.abi, signer)
}
// export function getElementExSwapContract(chainId: number, signer: Signer): Contract {
// const address = CONTRACTS_ADDRESSES[chainId as keyof typeof CONTRACTS_ADDRESSES].ElementExSwapV2
// return new Contract(address, ContractABI.elementExSwap.abi, signer)
// }
export function getHelperContract(chainId: number, signer: Signer): Contract {
const address = CONTRACTS_ADDRESSES[chainId as keyof typeof CONTRACTS_ADDRESSES].Helper
return new Contract(address, ContractABI.helper.abi, signer)
}
FILE:scripts/code/src/contracts/abi/common/ERC721.json
{
"contractName": "ERC721",
"abi": [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "approved",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "baseURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "getApproved",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "mint",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "uri",
"type": "string"
}
],
"name": "setBaseURI",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
}
FILE:scripts/code/src/contracts/abi/common/ERC1155.json
{
"contractName": "ERC1155",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "values",
"type": "uint256[]"
}
],
"name": "TransferBatch",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "TransferSingle",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "value",
"type": "string"
},
{
"indexed": true,
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "URI",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "accounts",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
}
],
"name": "balanceOfBatch",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"name": "batchMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mintTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeBatchTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "uri",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "exists",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "creator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "_getOverrideURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
FILE:scripts/code/src/contracts/abi/common/ERC20.json
{
"contractName": "ERC20",
"abi": [
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "who",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "owner",
"type": "address"
},
{
"indexed": true,
"name": "spender",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "spender",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
}
FILE:scripts/code/src/contracts/abi/common/WETH.json
{
"contractName": "WETH9",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Withdrawal",
"type": "event"
},
{
"payable": true,
"stateMutability": "payable",
"type": "fallback"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "guy",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "dst",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "src",
"type": "address"
},
{
"internalType": "address",
"name": "dst",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "withdraw",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
}
FILE:scripts/code/src/contracts/abi/index.ts
import ERC20Abi from './common/ERC20.json'
import ERC721Abi from './common/ERC721.json'
import ERC1155Abi from './common/ERC1155.json'
import WETHAbi from './common/WETH.json'
import IElementExAbi from './elementEx/IElementEx.json'
import IElementExSwapAbi from './elementEx/IElementExSwapV2.json'
import HelperAbi from './elementEx/IAggTraderHelper.json'
export interface AbiInfo {
contractName: string;
sourceName?: string;
abi: any;
}
export const ContractABI = {
weth: WETHAbi as AbiInfo,
erc20: ERC20Abi as AbiInfo,
erc721: ERC721Abi as AbiInfo,
erc1155: ERC1155Abi as AbiInfo,
elementEx: IElementExAbi as AbiInfo,
elementExSwap: IElementExSwapAbi as AbiInfo,
helper: HelperAbi as AbiInfo,
}
FILE:scripts/code/src/contracts/abi/elementEx/IElementExSwapV2.json
{
"_format": "hh-sol-artifact-1",
"contractName": "IElementExSwapV2",
"sourceName": "contracts/swap/IElementExSwapV2.sol",
"abi": [
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct IAggregator.ERC20Pair[]",
"name": "erc20Pairs",
"type": "tuple[]"
},
{
"internalType": "bytes",
"name": "tradeBytes",
"type": "bytes"
},
{
"internalType": "address[]",
"name": "dustTokens",
"type": "address[]"
}
],
"name": "batchBuyWithERC20s",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct IAggregator.ERC20Pair[]",
"name": "erc20Pairs",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "uint256",
"name": "marketId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "tradeData",
"type": "bytes"
}
],
"internalType": "struct ISimulator.TradeDetails[]",
"name": "tradeDetails",
"type": "tuple[]"
},
{
"internalType": "address[]",
"name": "dustTokens",
"type": "address[]"
}
],
"name": "batchBuyWithERC20sSimulate",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "tradeBytes",
"type": "bytes"
}
],
"name": "batchBuyWithETH",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "marketId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "tradeData",
"type": "bytes"
}
],
"internalType": "struct ISimulator.TradeDetails[]",
"name": "tradeDetails",
"type": "tuple[]"
}
],
"name": "batchBuyWithETHSimulate",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
FILE:scripts/code/src/contracts/abi/elementEx/IElementEx.json
{
"_format": "hh-sol-artifact-1",
"contractName": "IElementEx",
"sourceName": "contracts/element/IElementEx.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20FillAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct INFTOrdersFeature.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint128",
"name": "erc1155FillAmount",
"type": "uint128"
}
],
"name": "ERC1155BuyOrderFilled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"name": "ERC1155BuyOrderPreSigned",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "ERC1155OrderCancelled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20FillAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct INFTOrdersFeature.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint128",
"name": "erc1155FillAmount",
"type": "uint128"
}
],
"name": "ERC1155SellOrderFilled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"name": "ERC1155SellOrderPreSigned",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct INFTOrdersFeature.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc721Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
}
],
"name": "ERC721BuyOrderFilled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc721Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"name": "ERC721BuyOrderPreSigned",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "ERC721OrderCancelled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct INFTOrdersFeature.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc721Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
}
],
"name": "ERC721SellOrderFilled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"indexed": false,
"internalType": "address",
"name": "erc721Token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
}
],
"name": "ERC721SellOrderPreSigned",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newHashNonce",
"type": "uint256"
}
],
"name": "HashNonceIncremented",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "migrator",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "Migrated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes4",
"name": "selector",
"type": "bytes4"
},
{
"indexed": false,
"internalType": "address",
"name": "oldImpl",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "newImpl",
"type": "address"
}
],
"name": "ProxyFunctionUpdated",
"type": "event"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "signatures",
"type": "tuple[]"
},
{
"internalType": "uint128[]",
"name": "erc1155TokenAmounts",
"type": "uint128[]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "batchBuyERC1155s",
"outputs": [
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "signatures",
"type": "tuple[]"
},
{
"internalType": "address[]",
"name": "takers",
"type": "address[]"
},
{
"internalType": "uint128[]",
"name": "erc1155TokenAmounts",
"type": "uint128[]"
},
{
"internalType": "bytes[]",
"name": "takerDatas",
"type": "bytes[]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "batchBuyERC1155sEx",
"outputs": [
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "signatures",
"type": "tuple[]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "batchBuyERC721s",
"outputs": [
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "signatures",
"type": "tuple[]"
},
{
"internalType": "address[]",
"name": "takers",
"type": "address[]"
},
{
"internalType": "bytes[]",
"name": "takerDatas",
"type": "bytes[]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "batchBuyERC721sEx",
"outputs": [
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "signatures",
"type": "tuple[]"
},
{
"internalType": "address[]",
"name": "takers",
"type": "address[]"
},
{
"internalType": "uint128[]",
"name": "erc1155FillAmounts",
"type": "uint128[]"
},
{
"internalType": "bytes[]",
"name": "callbackData",
"type": "bytes[]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "batchBuySharedERC1155s",
"outputs": [
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "orderNonces",
"type": "uint256[]"
}
],
"name": "batchCancelERC1155Orders",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "orderNonces",
"type": "uint256[]"
}
],
"name": "batchCancelERC721Orders",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder[]",
"name": "buyOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "sellOrderSignatures",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "buyOrderSignatures",
"type": "tuple[]"
}
],
"name": "batchMatchERC1155Orders",
"outputs": [
{
"internalType": "uint256[]",
"name": "profits",
"type": "uint256[]"
},
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder[]",
"name": "buyOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "sellOrderSignatures",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "buyOrderSignatures",
"type": "tuple[]"
}
],
"name": "batchMatchERC721Orders",
"outputs": [
{
"internalType": "uint256[]",
"name": "profits",
"type": "uint256[]"
},
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder[]",
"name": "sellOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder[]",
"name": "buyOrders",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "sellOrderSignatures",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature[]",
"name": "buyOrderSignatures",
"type": "tuple[]"
}
],
"name": "batchMatchSharedERC1155Orders",
"outputs": [
{
"internalType": "uint256[]",
"name": "profits",
"type": "uint256[]"
},
{
"internalType": "bool[]",
"name": "successes",
"type": "bool[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
}
],
"name": "buyERC1155",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
},
{
"internalType": "bytes",
"name": "takerData",
"type": "bytes"
}
],
"name": "buyERC1155Ex",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "buyERC721",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "bytes",
"name": "takerData",
"type": "bytes"
}
],
"name": "buyERC721Ex",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
},
{
"internalType": "bytes",
"name": "callbackData",
"type": "bytes"
}
],
"name": "buySharedERC1155",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "orderNonce",
"type": "uint256"
}
],
"name": "cancelERC1155Order",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "orderNonce",
"type": "uint256"
}
],
"name": "cancelERC721Order",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "selector",
"type": "bytes4"
},
{
"internalType": "address",
"name": "impl",
"type": "address"
}
],
"name": "extend",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "data1",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "data2",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "data3",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "fee1",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "fee2",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct IBasicERC721OrdersFeature.BasicOrderParameter",
"name": "parameter",
"type": "tuple"
}
],
"name": "fillBasicERC721Order",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "parameter1",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "parameter2",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "parameter3",
"type": "uint256"
}
],
"internalType": "struct IBasicERC721OrdersFeature.BasicOrderParameters",
"name": "parameters",
"type": "tuple"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "uint256",
"name": "extra",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct IBasicERC721OrdersFeature.BasicOrderItem[]",
"name": "orders",
"type": "tuple[]"
}
],
"name": "fillBasicERC721Orders",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "data1",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "data2",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "data3",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct IBatchSignedERC721OrdersFeature.BatchSignedERC721OrderParameter",
"name": "parameter",
"type": "tuple"
},
{
"internalType": "bytes",
"name": "collections",
"type": "bytes"
}
],
"name": "fillBatchSignedERC721Order",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "data1",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "data2",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "data3",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "collections",
"type": "bytes"
}
],
"internalType": "struct IBatchSignedERC721OrdersFeature.BatchSignedERC721OrderParameters[]",
"name": "parameters",
"type": "tuple[]"
},
{
"internalType": "uint256",
"name": "additional1",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "additional2",
"type": "uint256"
}
],
"name": "fillBatchSignedERC721Orders",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155BuyOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155BuyOrderInfo",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "status",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "orderAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "remainingAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.OrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "uint248",
"name": "nonceRange",
"type": "uint248"
}
],
"name": "getERC1155OrderNonceStatusBitVector",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155SellOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155SellOrderInfo",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "status",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "orderAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "remainingAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.OrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721BuyOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721BuyOrderStatus",
"outputs": [
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "uint248",
"name": "nonceRange",
"type": "uint248"
}
],
"name": "getERC721OrderStatusBitVector",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721SellOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721SellOrderStatus",
"outputs": [
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "maker",
"type": "address"
}
],
"name": "getHashNonce",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "selector",
"type": "bytes4"
},
{
"internalType": "uint256",
"name": "idx",
"type": "uint256"
}
],
"name": "getRollbackEntryAtIndex",
"outputs": [
{
"internalType": "address",
"name": "impl",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "selector",
"type": "bytes4"
}
],
"name": "getRollbackLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "incrementHashNonce",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "buyOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "sellOrderSignature",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "buyOrderSignature",
"type": "tuple"
}
],
"name": "matchERC1155Orders",
"outputs": [
{
"internalType": "uint256",
"name": "profit",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "buyOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "sellOrderSignature",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "buyOrderSignature",
"type": "tuple"
}
],
"name": "matchERC721Orders",
"outputs": [
{
"internalType": "uint256",
"name": "profit",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "sellOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "buyOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "sellOrderSignature",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "buyOrderSignature",
"type": "tuple"
}
],
"name": "matchSharedERC1155Orders",
"outputs": [
{
"internalType": "uint256",
"name": "profit",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
},
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "migrate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "onERC1155Received",
"outputs": [
{
"internalType": "bytes4",
"name": "success",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "onERC721Received",
"outputs": [
{
"internalType": "bytes4",
"name": "success",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "ownerAddress",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "preSignERC1155BuyOrder",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "preSignERC1155SellOrder",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "preSignERC721BuyOrder",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "preSignERC721SellOrder",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "impl",
"type": "address"
},
{
"internalType": "bytes4[]",
"name": "methodIDs",
"type": "bytes4[]"
}
],
"name": "registerMethods",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "selector",
"type": "bytes4"
},
{
"internalType": "address",
"name": "targetImpl",
"type": "address"
}
],
"name": "rollback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "buyOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155SellAmount",
"type": "uint128"
},
{
"internalType": "bool",
"name": "unwrapNativeToken",
"type": "bool"
},
{
"internalType": "bytes",
"name": "takerData",
"type": "bytes"
}
],
"name": "sellERC1155",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "buyOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
},
{
"internalType": "bool",
"name": "unwrapNativeToken",
"type": "bool"
},
{
"internalType": "bytes",
"name": "takerData",
"type": "bytes"
}
],
"name": "sellERC721",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "buyOrder",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155SellAmount",
"type": "uint128"
},
{
"internalType": "bool",
"name": "unwrapNativeToken",
"type": "bool"
},
{
"internalType": "bytes",
"name": "callbackData",
"type": "bytes"
}
],
"name": "sellSharedERC1155",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[][]",
"name": "tokenIds",
"type": "uint256[][]"
}
],
"name": "transferERC721s",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[][]",
"name": "tokenIds",
"type": "uint256[][]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "transferERC721sEx",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"components": [
{
"internalType": "enum INFTransfersFeature.ItemType",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"internalType": "struct INFTransfersFeature.TransferItem[]",
"name": "items",
"type": "tuple[]"
}
],
"name": "transferItems",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"components": [
{
"internalType": "enum INFTransfersFeature.ItemType",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"internalType": "struct INFTransfersFeature.TransferItem[]",
"name": "items",
"type": "tuple[]"
},
{
"internalType": "bool",
"name": "revertIfIncomplete",
"type": "bool"
}
],
"name": "transferItemsEx",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC1155BuyOrderSignature",
"outputs": [],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC1155SellOrderSignature",
"outputs": [],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC721BuyOrderSignature",
"outputs": [],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC721SellOrderSignature",
"outputs": [],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
FILE:scripts/code/src/contracts/abi/elementEx/IAggTraderHelper.json
{
"_format": "hh-sol-artifact-1",
"contractName": "IAggTraderHelper",
"sourceName": "contracts/helper/IAggTraderHelper.sol",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "checkAssets",
"outputs": [
{
"components": [
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
}
],
"internalType": "struct IAssetCheckerFeature.AssetCheckResultInfo[]",
"name": "infos",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "uint8[]",
"name": "itemTypes",
"type": "uint8[]"
},
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "checkAssetsEx",
"outputs": [
{
"components": [
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
}
],
"internalType": "struct IAssetCheckerFeature.AssetCheckResultInfo[]",
"name": "infos",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "uint256",
"name": "listingTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "expirationTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "startNonce",
"type": "uint256"
},
{
"internalType": "address",
"name": "paymentToken",
"type": "address"
},
{
"internalType": "address",
"name": "platformFeeRecipient",
"type": "address"
},
{
"components": [
{
"internalType": "address",
"name": "nftAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "platformFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "royaltyFee",
"type": "uint256"
},
{
"internalType": "address",
"name": "royaltyFeeRecipient",
"type": "address"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItem[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollection[]",
"name": "basicCollections",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "address",
"name": "nftAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "platformFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "royaltyFee",
"type": "uint256"
},
{
"internalType": "address",
"name": "royaltyFeeRecipient",
"type": "address"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItem[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollection[]",
"name": "collections",
"type": "tuple[]"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSERC721Orders",
"name": "order",
"type": "tuple"
}
],
"name": "checkBSERC721Orders",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
},
{
"components": [
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"components": [
{
"internalType": "bool",
"name": "isNonceValid",
"type": "bool"
},
{
"internalType": "bool",
"name": "isERC20AmountValid",
"type": "bool"
},
{
"internalType": "address",
"name": "ownerOfNftId",
"type": "address"
},
{
"internalType": "address",
"name": "approvedAccountOfNftId",
"type": "address"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItemCheckResult[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollectionCheckResult[]",
"name": "basicCollections",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"components": [
{
"internalType": "bool",
"name": "isNonceValid",
"type": "bool"
},
{
"internalType": "bool",
"name": "isERC20AmountValid",
"type": "bool"
},
{
"internalType": "address",
"name": "ownerOfNftId",
"type": "address"
},
{
"internalType": "address",
"name": "approvedAccountOfNftId",
"type": "address"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItemCheckResult[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollectionCheckResult[]",
"name": "collections",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSERC721OrdersCheckResult",
"name": "r",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155SellAmount",
"type": "uint128"
}
],
"name": "checkERC1155BuyOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "ecr1155TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "sellAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155SellAmount",
"type": "uint128"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC1155BuyOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "ecr1155TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "sellAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
}
],
"name": "checkERC1155SellOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20WillPayAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "buyAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC1155SellOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20WillPayAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "buyAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
}
],
"name": "checkERC721BuyOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "bool",
"name": "ecr721TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC721BuyOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "bool",
"name": "ecr721TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
}
],
"name": "checkERC721SellOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC20CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC721SellOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC20CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155BuyOrderInfo",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "status",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "orderAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "remainingAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.OrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155SellOrderInfo",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "status",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "orderAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "remainingAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.OrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721BuyOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721SellOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "maker",
"type": "address"
}
],
"name": "getHashNonce",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "accountNonce",
"type": "uint256"
}
],
"name": "getLooksRareCheckInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "transferManager",
"type": "address"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isExecutedOrCancelled",
"type": "bool"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.LooksRareCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "accountNonce",
"type": "uint256"
}
],
"name": "getLooksRareCheckInfoEx",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "transferManager",
"type": "address"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isExecutedOrCancelled",
"type": "bool"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.LooksRareCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"components": [
{
"internalType": "uint8",
"name": "tokenType",
"type": "uint8"
},
{
"internalType": "address",
"name": "tokenAddress",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"internalType": "struct ISDKApproveCheckerFeature.SDKApproveInfo[]",
"name": "list",
"type": "tuple[]"
}
],
"name": "getSDKApprovalsAndCounter",
"outputs": [
{
"internalType": "uint256[]",
"name": "approvals",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "elementCounter",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "seaportCounter",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "conduitKey",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"name": "getSeaportCheckInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "conduit",
"type": "address"
},
{
"internalType": "bool",
"name": "conduitExists",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isValidated",
"type": "bool"
},
{
"internalType": "bool",
"name": "isCancelled",
"type": "bool"
},
{
"internalType": "uint256",
"name": "totalFilled",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSize",
"type": "uint256"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.SeaportCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "conduitKey",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"name": "getSeaportCheckInfoEx",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "conduit",
"type": "address"
},
{
"internalType": "bool",
"name": "conduitExists",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isValidated",
"type": "bool"
},
{
"internalType": "bool",
"name": "isCancelled",
"type": "bool"
},
{
"internalType": "uint256",
"name": "totalFilled",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSize",
"type": "uint256"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.SeaportCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "address",
"name": "executionDelegate",
"type": "address"
}
],
"name": "getX2y2CheckInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "enum IX2y2.InvStatus",
"name": "status",
"type": "uint8"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.X2y2CheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "isERC1155OrderNonceCancelled",
"outputs": [
{
"internalType": "bool",
"name": "filled",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "isERC721OrderNonceFilled",
"outputs": [
{
"internalType": "bool",
"name": "filled",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "ens",
"type": "address"
},
{
"internalType": "bytes32[]",
"name": "nodes",
"type": "bytes32[]"
}
],
"name": "queryENSInfosByNode",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "address",
"name": "domainAddr",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "bool",
"name": "available",
"type": "bool"
}
],
"internalType": "struct IENSHelperFeature.ENSQueryResult[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "ens",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "queryENSInfosByToken",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "address",
"name": "domainAddr",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "bool",
"name": "available",
"type": "bool"
}
],
"internalType": "struct IENSHelperFeature.ENSQueryResult[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "ens",
"type": "address"
},
{
"internalType": "address[]",
"name": "addresses",
"type": "address[]"
}
],
"name": "queryENSReverseInfos",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "bytes",
"name": "domain",
"type": "bytes"
},
{
"internalType": "address",
"name": "verifyResolver",
"type": "address"
},
{
"internalType": "address",
"name": "verifyAddr",
"type": "address"
}
],
"internalType": "struct IENSHelperFeature.ENSReverseResult[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "string[]",
"name": "names",
"type": "string[]"
},
{
"internalType": "bytes32[]",
"name": "secrets",
"type": "bytes32[]"
},
{
"internalType": "uint256[]",
"name": "durations",
"type": "uint256[]"
}
],
"name": "querySpaceIdInfos",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "minCommitAge",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxCommitAge",
"type": "uint256"
},
{
"components": [
{
"internalType": "uint256",
"name": "base",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "premium",
"type": "uint256"
},
{
"internalType": "bool",
"name": "available",
"type": "bool"
},
{
"internalType": "bytes32",
"name": "commitHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "commitTimestamp",
"type": "uint256"
}
],
"internalType": "struct ISpaceIdHelperFeature.SpaceIdItem[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct ISpaceIdHelperFeature.SpaceIdInfos",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC1155BuyOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC1155SellOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC721BuyOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC721SellOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
FILE:scripts/code/src/contracts/config.ts
export { ContractABI } from './abi/index'
export const CONTRACTS_ADDRESSES = {
1: {
ElementEx: '0x20F780A973856B93f63670377900C1d2a50a77c4',
ElementExSwapV2: '0xb4E7B8946fA2b35912Cc0581772cCCd69A33000c',
Helper: '0x68dc8D3ab93220e84b9923706B3DDc926C77f1Df',
WToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
},
11155111: {
ElementEx: '0x5df0d6a56523d49650a2526873c2c055201aa879',
ElementExSwapV2: '0xfb099ce799d8ea457cd7a4401d621c00d87c87fa',
Helper: '0x7a758546926f19b2dcffd114a36b3c8e04be7475',
WToken: '0x097d90c9d3e0b50ca60e1ae45f6a81010f9fb534'
},
56: {
ElementEx: '0xb3e3DfCb2d9f3DdE16d78B9e6EB3538Eb32B5ae1',
ElementExSwapV2: '0x46A03313FA8eF8ac8798f502bB38d35E5e1acbfC',
Helper: '0xb54ee46dACE4ecAC1dBC2488B61094B4b3174139',
WToken: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
},
97: {
ElementEx: '0x30FAD3918084eba4379FD01e441A3Bb9902f0843',
ElementExSwapV2: '0x8751796ba398412A1520fa177E421183C49a8780',
Helper: '0x61311202273f9857685852FC76aEA83294F90a80',
WToken: '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd'
},
137: {
ElementEx: '0xEAF5453b329Eb38Be159a872a6ce91c9A8fb0260',
ElementExSwapV2: '0x25956Fd0A5FE281D921b1bB3499fc8D5EFea6201',
Helper: '0x4D5E03AF11d7976a0494f0ff2F65986d6548fc3e',
WToken: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270'
},
80001: {
ElementEx: '0x2431e7671d1557d991a138c7af5d4cd223a605d6',
ElementExSwapV2: '0xA9fF4783fA66bc2774f2c41489BA570EbE82E141',
Helper: '0xcCcd0afEAfB6625cd655Cf8f39B02c85947dB6f6',
WToken: '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889'
},
43114: {
ElementEx: '0x18cd9270DbdcA86d470cfB3be1B156241fFfA9De',
ElementExSwapV2: '0x917ef4F231Cbd0972A10eC3453F40762C488e6fa',
Helper: '0x4c95419b74D420841CaaAd6345799522475f91D2',
WToken: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7'
},
43113: {
ElementEx: '0xd089757a20a36B0978156659Cc1063B929Da76aB',
ElementExSwapV2: '0x786596CFaA0020EC7fFdE499049E3b9981E99f4A',
Helper: '0x1f66918D87aab33158DBA4b5Dfe73f2245cfDc20',
WToken: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c'
},
42161: {
ElementEx: '0x18cd9270dbdca86d470cfb3be1b156241fffa9de',
ElementExSwapV2: '0x1e0E556b7f310c320bA22b5dEC0A0755C1c9854b',
Helper: '0xb4E7B8946fA2b35912Cc0581772cCCd69A33000c',
WToken: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1'
},
421613: {
ElementEx: '0x6938d12679ba4e646934a6900bd4077c3cc09a04',
ElementExSwapV2: '0xf6bD4a8dfe1FB577C311Bd361CB1b0e7DD3b83ab',
Helper: '0xccf79726adA5333B41793994fAe78a28F0c6278A',
WToken: '0x204a6679557ec1adfb3752c88891aa885adb53f1'
},
324: {
ElementEx: '0x64848eefbc2921102a153b08fa64536ae1f8e937',
ElementExSwapV2: '0x7868a55b638ed298370c16f83fa32b26664726ab',
Helper: '0x4ff83aa3a2a993270c7921ce6f22892213c3c446',
WToken: '0x5aea5775959fbc2557cc8789bc1bf90a239d9a91'
},
280: {
ElementEx: '0x0ec4d499f46a154e7faf52c1695b2da8a41900d4',
ElementExSwapV2: '0x448798ccc3a9d15ce5d4369c928c86b4085c106d',
Helper: '0xbc91448f965c684238686532f17492d207f0a9b7',
WToken: '0xf8dcf9b36817151d36ff2e35d9f43094dde4c737'
},
59144: {
ElementEx: '0x0caB6977a9c70E04458b740476B498B214019641',
ElementExSwapV2: '0x42c759a719c228050901299b88fd316c3a050617',
Helper: '0x701a4A5238AF84a9c4ed8a23DeE670069b44eEb7',
WToken: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
},
59140: {
ElementEx: '0xc23cf8BC7cD2f2Dcb2e151E81b8a1F9EA7c017B6',
ElementExSwapV2: '0x4B2C3677432a918F197B9c546d0844f53d374eB0',
Helper: '0x9A6324eBF46288FD872c08BA7C6e51fbb62dC259',
WToken: '0x2C1b868d6596a18e32E61B901E4060C872647b6C'
},
8453: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0x66950320086664429C69735318724Ae24ec0D835',
Helper: '0x217efe077801387d125fE98E1b61CDDA4D1364d2',
WToken: '0x4200000000000000000000000000000000000006'
},
84531: {
ElementEx: '0x8237A37FC696D944d4Cdb089A89443B55Cb5e7F9',
ElementExSwapV2: '0xcCcd0afEAfB6625cd655Cf8f39B02c85947dB6f6',
Helper: '0x89A34a7EDC273555bB11ba4484ec417B05df3a15',
WToken: '0x4200000000000000000000000000000000000006'
},
204: {
ElementEx: '0x5417c5215F239B8D04f9D9c04bF43034B35AD4BD',
ElementExSwapV2: '0x8629E04a83902721FBD816fE9d41FD2053DAC79b',
Helper: '0x3c19784F5247ca471E27eA1C604b48D266eb000C',
WToken: '0x4200000000000000000000000000000000000006'
},
10: { // optimism
ElementEx: '0x2317d8b224328644759319dffa2a5da77c72e0e9',
ElementExSwapV2: '0xc9605a76b0370e148b4a510757685949f13248c7',
Helper: '0xbe6461385106793d2099399358d233c934d41581',
WToken: '0x4200000000000000000000000000000000000006'
},
534352: { // scroll
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0x217efe077801387d125fe98e1b61cdda4d1364d2',
Helper: '0x17bab823e1b4716f9bbe9eefc274f55ddf4056fd',
WToken: '0x5300000000000000000000000000000000000004'
},
169: { // manta
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0xbcfa22a36e555c507092ff16c1af4cb74b8514c8',
Helper: '0x4bd6ff0413a095a79a855d83399a4850476be81e',
WToken: '0x0dc808adce2099a9f62aa87d9670745aba741746'
},
5000: { // mantle
ElementEx: '0x2fa13cf695ec51ded5b8e45ad0bef838ab17e2af',
ElementExSwapV2: '0x9f47921d360aee0651a4f1ed2c4892b4923f9e52',
Helper: '0x4c95419b74d420841caaad6345799522475f91d2',
WToken: '0x78c1b0c915c4faa5fffa6cabf0219da63d7f4cb8'
},
42766: { // zkfair
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0xc9605a76b0370e148b4a510757685949f13248c7',
Helper: '0x0fd3d35c4536134e48a6bc05558b8d870878e119',
WToken: '0xd33db7ec50a98164cc865dfaa64666906d79319c'
},
81457: { // blast
ElementEx: '0x4196b39157659bf0de9ebf6e505648b7889a39ce',
ElementExSwapV2: '0xe29799ca0b98ba41343a4ea52fe15ed7d5e05662',
Helper: '0x0fd3d35c4536134e48a6bc05558b8d870878e119',
WToken: '0x4300000000000000000000000000000000000004'
},
4200: { // merlin
ElementEx: '0x4196b39157659bf0de9ebf6e505648b7889a39ce',
ElementExSwapV2: '0xe4ac19434cef450ead2942fa9ab01ec8fc0cf181',
Helper: '0x917ef4f231cbd0972a10ec3453f40762c488e6fa',
WToken: '0xf6d226f9dc15d9bb51182815b320d3fbe324e1ba'
},
//mode
34443: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0x2473e8d725f7b3eCa344c272F110948D63280f96',
Helper: '0x66950320086664429C69735318724Ae24ec0D835',
WToken: '0x4200000000000000000000000000000000000006'
},
//cyber
7560: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0xF937CDf1c6457c9b22ecC8310CE7c6374cF78353',
Helper: '0x4c95419b74D420841CaaAd6345799522475f91D2',
WToken: '0x4200000000000000000000000000000000000006'
},
//bob
60808: {
ElementEx: '0x2fa13cf695EC51Ded5B8E45Ad0BEf838aB17E2aF',
ElementExSwapV2: '0x2040491367062EA1Ae1c73Bc3961c6D0151Aa39f',
Helper: '0xfE357D8d1B285C846185b4Cae4F96bD81DF19445',
WToken: '0x4200000000000000000000000000000000000006'
},
// lightlink
1890: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0x66950320086664429C69735318724Ae24ec0D835',
Helper: '0x26Df6Fea89f1C9e4A3A2bfc2128542B7a05FbA8E',
WToken: '0x7EbeF2A4b1B09381Ec5B9dF8C5c6f2dBECA59c73'
},
//zeta
7000: {
ElementEx: '0x4196b39157659BF0De9ebF6E505648B7889a39cE',
ElementExSwapV2: '0x9f47921D360aeE0651A4F1ED2c4892B4923F9E52',
Helper: '0x66950320086664429C69735318724Ae24ec0D835',
WToken: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
},
//nibiru
6900: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0xf71a05E3749b0F9611307A37AFE3d853Bd734E13',
Helper: '0xbe6461385106793d2099399358D233C934d41581',
WToken: '0x0CaCF669f8446BeCA826913a3c6B96aCD4b02a97'
},
//abstract
2741: {
ElementEx: '0x3f33a3dab9e6f691a11D0EEBDf93dA445A021096',
ElementExSwapV2: '0xA4306F9CeFC471447580C617905F49d43Df1Ece9',
Helper: '0xb82F08665d2DDD19F219FadD6e01701E876D41eC',
WToken: '0x3439153EB7AF838Ad19d56E1571FBD09333C2809'
},
//monad
143: {
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0x42c759a719c228050901299b88fd316c3a050617',
Helper: '0x701a4a5238af84a9c4ed8a23dee670069b44eeb7',
WToken: '0x3bd359c1119da7da1d913d1c4d2b7c461115433a'
},
//bitlayer
200901: {
ElementEx: '0x0caB6977a9c70E04458b740476B498B214019641',
ElementExSwapV2: '0xa52C8a12C728e95f1BeF74835b1316b7407b61A8',
Helper: '0xe29799cA0B98BA41343A4eA52Fe15ed7D5e05662',
WToken: '0xfF204e2681A6fA0e2C3FaDe68a1B28fb90E4Fc5F'
},
}
const RPC_URLS = {
1: 'https://api.zan.top/node/v1/eth/mainnet/6e96cfbcaff949bfbdaeb5fbc554ac7c',
}
// RPC 配置 API 地址
export const RPC_CONF_API_URL = 'https://api.element.market/v1/quote/rpcConfInfo'
// RPC 配置信息接口
export interface RpcConfInfo {
chainMId: number
rpcUrl: string
isWalletPriority: boolean
}
// RPC 配置响应接口
export interface RpcConfResponse {
code: number
status: string
data: RpcConfInfo[]
}
// 缓存的 RPC 配置
let cachedRpcConfigs: Map<number, RpcConfInfo> | null = null
let lastFetchTime: number = 0
const CACHE_DURATION = 5 * 60 * 1000 // 5 分钟缓存
/**
* 从 HTTP 接口获取所有 RPC 配置
* @returns Promise<RpcConfInfo[]> RPC 配置列表
*/
export async function fetchRpcConfigs(): Promise<RpcConfInfo[]> {
try {
const response = await fetch(RPC_CONF_API_URL)
if (!response.ok) {
throw new Error(`HTTP error! status: response.status`)
}
const result = await response.json() as RpcConfResponse
if (result.code !== 0) {
throw new Error(`API error: result.status`)
}
return result.data
} catch (error) {
console.error('Failed to fetch RPC configs:', error)
throw error
}
}
/**
* 获取缓存的 RPC 配置(带缓存机制)
* @returns Promise<Map<number, RpcConfInfo>> 链 ID 到 RPC 配置的映射
*/
export async function getCachedRpcConfigs(): Promise<Map<number, RpcConfInfo>> {
const now = Date.now()
if (cachedRpcConfigs && now - lastFetchTime < CACHE_DURATION) {
return cachedRpcConfigs
}
const configs = await fetchRpcConfigs()
const filteredConfigs = configs.filter(config => !config.isWalletPriority)
cachedRpcConfigs = new Map(filteredConfigs.map(config => [config.chainMId, config]))
// 将 RPC_URLS 中的静态配置也加入缓存
Object.entries(RPC_URLS).forEach(([chainMId, rpcUrl]) => {
if (!cachedRpcConfigs!.has(parseInt(chainMId))) {
cachedRpcConfigs!.set(parseInt(chainMId), {
chainMId: parseInt(chainMId),
rpcUrl,
isWalletPriority: false
})
}
})
lastFetchTime = now
return cachedRpcConfigs
}
/**
* 从远程获取指定链的 RPC URL
* @param chainId 链 ID
* @returns Promise<string | undefined> RPC URL
*/
export async function getRpcUrlFromRemote(chainMId: number): Promise<string | undefined> {
try {
const configs = await getCachedRpcConfigs()
const config = configs.get(chainMId)
return config?.rpcUrl
} catch (error) {
console.error(`Failed to get RPC URL for chain chainMId from remote:`, error)
return undefined
}
}
FILE:scripts/code/src/element/order/orderTypedData.ts
import { ERC1155Order, ERC721Order } from './orderTypes'
import { CONTRACTS_ADDRESSES } from '../../contracts/config'
const FEE_ABI = [
{ type: 'address', name: 'recipient' },
{ type: 'uint256', name: 'amount' },
{ type: 'bytes', name: 'feeData' }
]
const PROPERTY_ABI = [
{ type: 'address', name: 'propertyValidator' },
{ type: 'bytes', name: 'propertyData' }
]
// ERC721Order EIP712 information
const STRUCT_ERC721_SELL_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'nft' },
{ type: 'uint256', name: 'nftId' },
{ type: 'uint256', name: 'hashNonce' }
]
const STRUCT_ERC721_BUY_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'nft' },
{ type: 'uint256', name: 'nftId' },
{ type: 'Property[]', name: 'nftProperties' },
{ type: 'uint256', name: 'hashNonce' }
]
// ERC1155Order EIP712 information
const STRUCT_ERC1155_SELL_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'erc1155Token' },
{ type: 'uint256', name: 'erc1155TokenId' },
{ type: 'uint128', name: 'erc1155TokenAmount' },
{ type: 'uint256', name: 'hashNonce' }
]
const STRUCT_ERC1155_BUY_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'erc1155Token' },
{ type: 'uint256', name: 'erc1155TokenId' },
{ type: 'Property[]', name: 'erc1155TokenProperties' },
{ type: 'uint128', name: 'erc1155TokenAmount' },
{ type: 'uint256', name: 'hashNonce' }
]
export function getOrderTypedData(order: ERC721Order | ERC1155Order, chainId: number) {
if (order['nft'] != undefined) {
return getERC721TypedData(order as ERC721Order, chainId)
} else {
return getERC1155TypedData(order as ERC1155Order, chainId)
}
}
function getERC721TypedData(order: ERC721Order, chainId: number) {
if (order.nftProperties == null) {
// ERC721SellOrder
return {
types: {
['NFTSellOrder']: STRUCT_ERC721_SELL_ORDER_ABI,
['Fee']: FEE_ABI
},
domain: getDomain(chainId),
primaryType: 'NFTSellOrder',
message: order as any
}
} else {
// ERC721BuyOrder
return {
types: {
['NFTBuyOrder']: STRUCT_ERC721_BUY_ORDER_ABI,
['Fee']: FEE_ABI,
['Property']: PROPERTY_ABI
},
domain: getDomain(chainId),
primaryType: 'NFTBuyOrder',
message: order as any
}
}
}
function getERC1155TypedData(order: ERC1155Order, chainId: number) {
if (order.erc1155TokenProperties == undefined) {
// ERC1155SellOrder
return {
types: {
['ERC1155SellOrder']: STRUCT_ERC1155_SELL_ORDER_ABI,
['Fee']: FEE_ABI
},
domain: getDomain(chainId),
primaryType: 'ERC1155SellOrder',
message: order as any
}
} else {
// ERC1155BuyOrder
return {
types: {
['ERC1155BuyOrder']: STRUCT_ERC1155_BUY_ORDER_ABI,
['Fee']: FEE_ABI,
['Property']: PROPERTY_ABI
},
domain: getDomain(chainId),
primaryType: 'ERC1155BuyOrder',
message: order as any
}
}
}
function getDomain(chainId: number) {
return {
name: 'ElementEx',
version: '1.0.0',
chainId: chainId,
verifyingContract: CONTRACTS_ADDRESSES[chainId].ElementEx.toLowerCase()
}
}
FILE:scripts/code/src/element/order/orderTypes.ts
import { AssetSchema, OrderSide, SaleKind } from '../../types/types'
export const DEFAULT_EXPIRATION_TIME = (7 * 86400)
export const MAX_EXPIRATION_TIME = (365 * 86400)
export const MAX_LISTING_TIME = (365 * 86400)
export interface Fee {
recipient: string;
amount: string;
feeData: string;
}
export interface Property {
propertyValidator: string;
propertyData: string;
}
export enum SignatureType {
EIP712,
PRESIGNED
}
export interface Signature {
signatureType: SignatureType;
v: number;
r: string;
s: string;
}
export interface ERC721Order {
maker: string;
taker: string;
expiry: string;
nonce: string;
erc20Token: string;
erc20TokenAmount: string;
fees: Fee[];
nft: string;
nftId: string;
nftProperties?: Property[];
hashNonce: string;
}
export interface ERC1155Order {
maker: string;
taker: string;
expiry: string;
nonce: string;
erc20Token: string;
erc20TokenAmount: string;
fees: Fee[];
erc1155Token: string;
erc1155TokenId: string;
erc1155TokenAmount: string;
erc1155TokenProperties?: Property[];
hashNonce: string;
}
export interface SignedOrder {
chainId: number;
order: ERC721Order | ERC1155Order;
signature: Signature;
orderHash: string;
}
export interface AssetRequest {
id: string;
address: string;
}
export interface Metadata {
asset: AssetRequest;
schema: AssetSchema;
}
export interface OrderRequest {
exchange: string;
chain: string;
maker: string;
taker: string;
side: OrderSide;
saleKind: SaleKind;
oracleSignature: number;
paymentToken: string;
quantity: string;
basePrice: string | number;
extra: string | number;
listingTime: number;
expirationTime: number;
metadata: Metadata;
fees: Fee[];
properties?: Property[];
nonce: string | number;
hashNonce: string | number;
signatureType: SignatureType;
v: number;
r: string;
s: string;
hash: string;
}
export interface CreateOrderParams {
makerAddress: string;
takerAddress: string;
asset: {
id?: string;
address: string;
schema: AssetSchema | string;
};
quantity?: string;
paymentToken?: string;
startTokenAmount: string;
platformFeePoint: number;
platformFeeAddress?: string;
royaltyFeePoint: number;
royaltyFeeAddress?: string;
listingTime?: number;
expirationTime?: number;
nonce: string;
saleKind?: SaleKind;
oracleSignature: number;
}
FILE:scripts/code/src/element/order/orderConverter.ts
import { BigNumber, ethers } from 'ethers'
import { ERC1155Order, ERC721Order, Fee, OrderRequest, Property, SignedOrder } from './orderTypes'
import { getChain } from '../../util/chainUtil'
import { CONTRACTS_ADDRESSES } from '../../contracts/config'
import { AssetSchema, OrderInformation, OrderSide, SaleKind, Standard } from '../../types/types'
import { encodeBits } from '../../util/bitsUtil'
import { toStandardERC20Token } from '../../util/tokenUtil'
export function toOrderInformation(order: OrderRequest, orderId: string): OrderInformation {
let price = order.basePrice
if (order.quantity) {
price = BigNumber.from(order.basePrice).div(order.quantity).toString()
}
return {
contractAddress: order.metadata.asset.address,
tokenId: order.metadata.asset.id,
schema: order.metadata.schema,
standard: Standard.ElementEx,
maker: order.maker,
listingTime: Number(order.listingTime),
expirationTime: Number(order.expirationTime),
price: Number(ethers.utils.formatEther(price)),
paymentToken: order.paymentToken,
saleKind: order.saleKind,
side: order.side,
orderId
}
}
export function toOrderRequest(signedOrder: SignedOrder): OrderRequest {
const { order, signature, chainId } = signedOrder
const chain = getChain(chainId)
const exchange = CONTRACTS_ADDRESSES[chainId].ElementEx
const info = parseOrder(order)
const expiry = decodeExpiry(order.expiry)
const totalERC20Amount = calcTotalERC20Amount(order)
const paymentToken = toStandardERC20Token(order.erc20Token)
const request: OrderRequest = {
exchange: exchange.toLowerCase(),
maker: order.maker.toLowerCase(),
taker: order.taker.toLowerCase(),
side: info.side,
saleKind: expiry.saleKind,
oracleSignature: expiry.oracleSignature,
paymentToken: paymentToken,
quantity: info.quantity,
basePrice: totalERC20Amount,
extra: expiry.extra,
listingTime: expiry.listingTime,
expirationTime: expiry.expirationTime,
metadata: info.metadata,
fees: toLowerCaseFees(order.fees),
nonce: order.nonce,
hashNonce: order.hashNonce,
hash: signedOrder.orderHash,
signatureType: signature.signatureType,
v: signature.v,
r: signature.r,
s: signature.s,
chain: chain
}
if (info.properties != null) {
request.properties = toLowerCaseProperties(info.properties)
if (request.properties.length > 0) {
request.saleKind = SaleKind.ContractOffer
}
}
return request
}
function toLowerCaseFees(fees: Fee[]): Fee[] {
return fees.map(fee => ({
recipient: fee.recipient.toLowerCase(),
amount: BigNumber.from(fee.amount).toString(),
feeData: fee.feeData
}))
}
function toLowerCaseProperties(properties: Property[]): Property[] {
return properties.map(property => ({
propertyValidator: property.propertyValidator.toLowerCase(),
propertyData: property.propertyData
}))
}
function calcTotalERC20Amount(order: ERC721Order | ERC1155Order): string {
let total = BigNumber.from(order.erc20TokenAmount)
for (let i = 0; i < order.fees.length; i++) {
total = total.add(order.fees[i].amount)
}
return total.toString()
}
function parseOrder(order: ERC721Order | ERC1155Order) {
let side: OrderSide
let quantity: string
let metadata
let properties
if (order['nft'] != undefined) {
quantity = '1'
metadata = {
asset: {
id: order['nftId'],
address: order['nft'].toString().toLowerCase()
},
schema: AssetSchema.ERC721
}
if (order['nftProperties'] != undefined) {
side = OrderSide.BuyOrder
properties = toLowerCaseProperties(order['nftProperties'])
} else {
side = OrderSide.SellOrder
properties = undefined
}
} else if (order['erc1155Token'] != undefined) {
quantity = order['erc1155TokenAmount']
metadata = {
asset: {
id: order['erc1155TokenId'],
address: order['erc1155Token'].toString().toLowerCase()
},
schema: AssetSchema.ERC1155
}
if (order['erc1155TokenProperties'] != undefined) {
side = OrderSide.BuyOrder
properties = toLowerCaseProperties(order['erc1155TokenProperties'])
} else {
side = OrderSide.SellOrder
properties = undefined
}
} else {
throw Error('toOrderStr error')
}
return { side, quantity, metadata, properties }
}
function decodeExpiry(expiry: string) {
// saleKind (4bit) + reserved(156bit) + extra(32bit) + listingTime(32bit) + expiryTime(32bit) = 256bit
const hex = encodeBits([ [ expiry, 256 ] ]).substring(2)
const orderSaleKindHex = '0x' + hex.substring(0, 1)
const oracleSignatureHex = '0x' + hex.substring(1, 2)
const extraHex = '0x' + hex.substring(40, 48)
const listingTimeHex = '0x' + hex.substring(48, 56)
const expiryTimeHex = '0x' + hex.substring(56, 64)
return {
saleKind: parseInt(orderSaleKindHex),
oracleSignature: parseInt(oracleSignatureHex),
extra: parseInt(extraHex).toString(),
listingTime: parseInt(listingTimeHex),
expirationTime: parseInt(expiryTimeHex)
}
}
FILE:scripts/code/src/element/order/orderManager.ts
import { LimitedCallSpec, Web3Signer } from "../../signer/Web3Signer";
import {
getElementExContract,
getHelperContract,
} from "../../contracts/contracts";
import { CONTRACTS_ADDRESSES } from "../../contracts/config";
import { BigNumber } from "ethers";
import {
CreateOrderParams,
DEFAULT_EXPIRATION_TIME,
ERC1155Order,
ERC721Order,
Fee,
MAX_EXPIRATION_TIME,
MAX_LISTING_TIME,
SignatureType,
SignedOrder,
} from "./orderTypes";
import {
AssetSchema,
ETH_TOKEN_ADDRESS,
GasParams,
NULL_ADDRESS,
SaleKind,
} from "../../types/types";
import { toContractERC20Token } from "../../util/tokenUtil";
import { getOrderTypedData } from "./orderTypedData";
import { encodeBits } from "../../util/bitsUtil";
import { TransactionResponse } from "@ethersproject/abstract-provider";
export class OrderManager {
public web3Signer: Web3Signer;
public WETH: string;
constructor(web3Signer: Web3Signer) {
this.web3Signer = web3Signer;
this.WETH = CONTRACTS_ADDRESSES[web3Signer.chainId].WToken;
}
public async cancelERC721Orders(
signedOrders: any[],
gasParams: GasParams,
): Promise<TransactionResponse> {
const nonces: any[] = [];
for (const signedOrder of signedOrders) {
nonces.push(
signedOrder.order ? signedOrder.order.nonce : signedOrder.nonce,
);
}
const elementEx = await this.getElementEx();
const tx =
await elementEx.populateTransaction.batchCancelERC721Orders(nonces);
if (!tx?.data) {
throw Error("cancelOrder failed, populateTransaction error.");
}
const from = await this.web3Signer.getCurrentAccount();
const call: LimitedCallSpec = {
from: from,
to: elementEx.address,
data: tx.data,
gasPrice: gasParams.gasPrice,
maxPriorityFeePerGas: gasParams.maxPriorityFeePerGas,
maxFeePerGas: gasParams.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
public async createSellOrder(
params: CreateOrderParams,
gasParams: GasParams,
): Promise<ERC721Order | ERC1155Order> {
const expiry = getOrderExpiry(params);
const fees = calcFees(params);
const erc20TokenAmount = calcERC20TokenAmount(params, fees);
const order: any = {
maker: params.makerAddress.toLowerCase(),
taker: params.takerAddress.toLowerCase(),
expiry: expiry,
nonce: BigNumber.from(params.nonce).toString(),
erc20Token: toContractERC20Token(params.paymentToken),
erc20TokenAmount: erc20TokenAmount,
fees: fees,
};
switch (params.asset.schema) {
case AssetSchema.ERC721:
order.nft = params.asset.address.toLowerCase();
order.nftId = BigNumber.from(params.asset.id).toString();
break;
case AssetSchema.ERC1155:
order.erc1155Token = params.asset.address.toLowerCase();
order.erc1155TokenId = BigNumber.from(params.asset.id).toString();
order.erc1155TokenAmount = BigNumber.from(params.quantity).toString();
break;
default:
throw Error(
"createSellOrder failed, unsupported schema : " + params.asset.schema,
);
}
await this.checkAndApproveSellOrder(order, gasParams);
return order;
}
public async createBuyOrder(
params: CreateOrderParams,
gasParams: GasParams,
): Promise<ERC721Order | ERC1155Order> {
const expiry = getOrderExpiry(params);
const fees = calcFees(params);
const erc20TokenAmount = calcERC20TokenAmount(params, fees);
const paymentToken = params.paymentToken ? params.paymentToken : this.WETH;
const order: any = {
maker: params.makerAddress.toLowerCase(),
taker: params.takerAddress.toLowerCase(),
expiry: expiry,
nonce: BigNumber.from(params.nonce).toString(),
erc20Token: toContractERC20Token(paymentToken),
erc20TokenAmount: erc20TokenAmount,
fees: fees,
};
const { tokenId, properties } = getBuyOrderTokenIdAndProperties(params);
switch (params.asset.schema) {
case AssetSchema.ERC721:
order.nft = params.asset.address.toLowerCase();
order.nftId = tokenId;
order.nftProperties = properties;
break;
case AssetSchema.ERC1155:
order.erc1155Token = params.asset.address.toLowerCase();
order.erc1155TokenId = tokenId;
order.erc1155TokenAmount = BigNumber.from(params.quantity).toString();
order.erc1155TokenProperties = properties;
break;
default:
throw Error(
"createBuyOrder failed, unsupported schema : " + params.asset.schema,
);
}
await this.checkAndApproveBuyOrder(order, gasParams);
return order;
}
public async signOrder(order: any): Promise<SignedOrder> {
const chainId = this.web3Signer.chainId;
const typedData = getOrderTypedData(order, chainId);
const signature = await this.web3Signer.signTypedData(
order.maker,
typedData,
);
const orderHash = Web3Signer.getOrderHash(typedData);
return {
chainId: chainId,
order: order,
signature: {
signatureType: SignatureType.EIP712,
v: signature.v,
r: signature.r,
s: signature.s,
},
orderHash: orderHash,
};
}
public async cancelERC1155Orders(
signedOrders: any[],
gasParams: GasParams,
): Promise<TransactionResponse> {
const nonces: any[] = [];
for (const signedOrder of signedOrders) {
nonces.push(signedOrder.order.nonce);
}
const elementEx = await this.getElementEx();
const tx =
await elementEx.populateTransaction.batchCancelERC1155Orders(nonces);
if (!tx?.data) {
throw Error("cancelOrder failed, populateTransaction error.");
}
const from = await this.web3Signer.getCurrentAccount();
const call: LimitedCallSpec = {
from: from,
to: elementEx.address,
data: tx.data,
gasPrice: gasParams.gasPrice,
maxPriorityFeePerGas: gasParams.maxPriorityFeePerGas,
maxFeePerGas: gasParams.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
public async cancelAllOrders(
gasParams?: GasParams,
): Promise<TransactionResponse> {
const elementEx = await this.getElementEx();
const tx = await elementEx.populateTransaction.incrementHashNonce();
if (!tx?.data) {
throw Error("cancelAllOrders failed, populateTransaction error.");
}
const from = await this.web3Signer.getCurrentAccount();
const call: LimitedCallSpec = {
from: from,
to: elementEx.address,
data: tx.data,
gasPrice: gasParams?.gasPrice,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas,
maxFeePerGas: gasParams?.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
private async getElementEx() {
const signer = await this.web3Signer.getSigner();
return getElementExContract(this.web3Signer.chainId, signer);
}
private async getHelper() {
const signer = await this.web3Signer.getSigner();
return getHelperContract(this.web3Signer.chainId, signer);
}
private async checkAndApproveSellOrder(
order: ERC721Order | ERC1155Order,
gasParams: GasParams,
) {
const isERC721Order = order["nft"] != null;
const helper = await this.getHelper();
const elementEx = await this.getElementEx();
const r = isERC721Order
? await helper.checkERC721SellOrder(order, NULL_ADDRESS)
: await helper.checkERC1155SellOrder(order, NULL_ADDRESS, "0");
order.hashNonce = r.info?.hashNonce?.toString();
if (r.info.success) {
return;
}
if (!r.info.makerCheck) {
throw Error("createSellOrder failed, makerCheck error.");
}
if (!r.info.takerCheck) {
throw Error("createSellOrder failed, takerCheck error.");
}
if (!r.info.listingTimeCheck) {
throw Error("createSellOrder failed, listingTimeCheck error.");
}
if (!r.info.expireTimeCheck) {
throw Error("createSellOrder failed, expireTimeCheck error.");
}
if (!r.info.extraCheck) {
throw Error("createSellOrder failed, extraCheck error.");
}
if (!r.info.feesCheck) {
throw Error("createSellOrder failed, feesCheck error.");
}
if (!r.info.nonceCheck) {
throw Error(
"createSellOrder failed, nonceCheck error, please try again.",
);
}
if (!r.info.erc20AddressCheck) {
throw Error("createSellOrder failed, erc20AddressCheck error.");
}
if (isERC721Order) {
if (!r.info.erc721OwnerCheck) {
throw Error(
`createSellOrder, erc721OwnerCheck failed, make sure account(order.maker) is owner of assetId(order["nftId"]).`,
);
}
if (!r.info.erc721ApprovedCheck) {
console.log("start approveERC721, ERC721Address =", order["nft"]);
const tx = await this.web3Signer.approveERC721Proxy(
order.maker,
order["nft"],
elementEx.address,
gasParams,
);
console.log("approveERC721, tx.hash", tx.hash);
await tx.wait();
console.log("approveERC721, completed.");
}
} else {
if (
order["erc1155TokenAmount"] == null ||
BigNumber.from(order["erc1155TokenAmount"]).lt("1")
) {
throw Error(
"createSellOrder, quantityCheck failed, erc1155 should set quantity.",
);
}
if (!r.info.remainingAmountCheck) {
throw Error(
"createSellOrder, remainingAmountCheck failed, please try again.",
);
}
if (!r.info.erc1155BalanceCheck) {
throw Error(
`createSellOrder, erc1155BalanceCheck failed, account(order.maker), require erc1155Balance >= quantity`,
);
}
if (!r.info.erc1155ApprovedCheck) {
console.log(
"start approveERC1155, ERC1155Address =",
order["erc1155Token"],
);
const tx = await this.web3Signer.approveERC1155Proxy(
order.maker,
order["erc1155Token"],
elementEx.address,
gasParams,
);
console.log("approveERC1155, tx.hash", tx.hash);
await tx.wait();
console.log("approveERC1155, completed.");
}
}
}
private async checkAndApproveBuyOrder(
order: ERC721Order | ERC1155Order,
gasParams: GasParams,
) {
const isERC721Order = "nft" in order;
const helper = await this.getHelper();
const elementEx = await this.getElementEx();
const r = isERC721Order
? await helper.checkERC721BuyOrder(order, NULL_ADDRESS, "0")
: await helper.checkERC1155BuyOrder(order, NULL_ADDRESS, "0", "0");
order.hashNonce = r.info?.hashNonce?.toString();
if (r.info.success) {
return;
}
if (!r.info.makerCheck) {
throw Error("createBuyOrder, makerCheck failed.");
}
if (!r.info.takerCheck) {
throw Error("createBuyOrder, takerCheck failed.");
}
if (!r.info.listingTimeCheck) {
throw Error("createBuyOrder, listingTimeCheck failed.");
}
if (!r.info.expireTimeCheck) {
throw Error("createBuyOrder, expireTimeCheck failed.");
}
if (!r.info.feesCheck) {
throw Error("createBuyOrder, feesCheck failed.");
}
if (!r.info.nonceCheck) {
throw Error("createBuyOrder, nonceCheck failed, please try again.");
}
if (!r.info.erc20AddressCheck) {
throw Error(
"createBuyOrder, erc20AddressCheck failed, should be ERC20 address, can not be native address.",
);
}
if (!r.info.propertiesCheck) {
throw Error("createBuyOrder, propertiesCheck failed.");
}
if (!isERC721Order) {
if (
order["erc1155TokenAmount"] == null ||
BigNumber.from(order["erc1155TokenAmount"]).lt("1")
) {
throw Error(
"createBuyOrder, quantityCheck failed, quantity: " +
order["erc1155TokenAmount"],
);
}
if (!r.info.remainingAmountCheck) {
throw Error(
"createBuyOrder, remainingAmountCheck failed, please try again.",
);
}
}
if (!r.info.erc20BalanceCheck) {
throw Error(
`createBuyOrder, erc20BalanceCheck failed, make sure accountorder.maker have enough balance of erc20Token(order.erc20Token).`,
);
}
if (
!r.info.erc20AllowanceCheck &&
order.erc20Token.toLowerCase() != ETH_TOKEN_ADDRESS
) {
console.log("start approveERC20, ERC20Address =", order.erc20Token);
const tx = await this.web3Signer.approveERC20Proxy(
order.maker,
order.erc20Token,
elementEx.address,
gasParams,
);
console.log("approveERC20, tx.hash", tx.hash);
await tx.wait(1);
console.log("approveERC20, completed.");
}
}
}
function calcFees(params: CreateOrderParams): Fee[] {
const fees: Fee[] = [];
const totalAmount = BigNumber.from(params.startTokenAmount);
if (params.platformFeePoint && params.platformFeeAddress) {
fees.push({
recipient: params.platformFeeAddress,
amount: totalAmount.mul(params.platformFeePoint).div(10000).toString(),
feeData: "0x",
});
}
if (params.royaltyFeePoint && params.royaltyFeeAddress) {
fees.push({
recipient: params.royaltyFeeAddress,
amount: totalAmount.mul(params.royaltyFeePoint).div(10000).toString(),
feeData: "0x",
});
}
return fees;
}
function calcERC20TokenAmount(params: CreateOrderParams, fees: Fee[]): string {
let amount = BigNumber.from(params.startTokenAmount);
for (const fee of fees) {
amount = amount.sub(fee.amount);
}
return amount.toString();
}
function getOrderExpiry(params: CreateOrderParams): string {
if (params.saleKind == null || params.saleKind == SaleKind.FixedPrice) {
const { listingTime, expirationTime } = getOrderTimeOfFixedPrice(params);
// saleKind (4bit) + oracleSignature(4bit) + reserved(152bit) + extra(32bit) + listingTime(32bit) + expiryTime(32bit) = 256bit
return encodeBits([
[0, 4],
[params.oracleSignature, 4],
[0, 152],
[0, 32],
[listingTime, 32],
[expirationTime, 32],
]);
}
throw Error("createOrder failed, unsupported saleKind : " + params.saleKind);
}
function getOrderTimeOfFixedPrice(params: CreateOrderParams) {
const now = Math.floor(Date.now() / 1000);
let listingTime;
if (params.listingTime) {
listingTime = params.listingTime;
if (listingTime > now + MAX_LISTING_TIME) {
throw Error("makeOrder failed, require listingTime <= now + 1 year.");
}
if (listingTime < now - 1800) {
throw Error("makeOrder failed, listingTime >= now - 30 minute.");
}
} else {
listingTime = now - 60;
}
let expirationTime;
if (params.expirationTime != null) {
expirationTime = params.expirationTime;
if (expirationTime < Math.max(listingTime, now)) {
throw Error(
"makeOrder failed, require expirationTime >= Math.max(listingTime, now).",
);
}
if (expirationTime > Math.max(listingTime, now) + MAX_EXPIRATION_TIME) {
throw Error(
"makeOrder failed, require expirationTime <= Math.max(listingTime, now) + 1 year.",
);
}
} else {
expirationTime = Math.max(listingTime, now) + DEFAULT_EXPIRATION_TIME;
}
return { listingTime, expirationTime };
}
function getBuyOrderTokenIdAndProperties(params: CreateOrderParams) {
if (params.asset.id == null) {
return {
tokenId: "0",
properties: [
{
propertyValidator: NULL_ADDRESS,
propertyData: "0x",
},
],
};
} else {
return {
tokenId: BigNumber.from(params.asset.id).toString(),
properties: [],
};
}
}
FILE:scripts/code/src/element/batchSignedOrder/batchSignedTypes.ts
export interface OrderItem {
erc20TokenAmount: string;
nftId: string;
}
export interface Collection {
nftAddress: string;
platformFee: number;
royaltyFeeRecipient: string;
royaltyFee: number;
items: OrderItem[];
}
export interface BatchSignedERC721Order {
exchange: string;
maker: string;
listingTime: number;
expirationTime: number;
startNonce: number;
paymentToken: string;
platformFeeRecipient: string;
basicCollections: Collection[];
collections: Collection[];
hashNonce: string;
oracleSignature: number;
chain: string;
}
export interface BatchSignedERC721OrderRequest extends BatchSignedERC721Order {
v: number;
r: string;
s: string;
hash: string;
}
export interface BatchSignedERC721OrderResponse extends BatchSignedERC721OrderRequest {
nonce: number;
}
FILE:scripts/code/src/element/batchSignedOrder/batchSignedTypedData.ts
import { toContractERC20Token } from '../../util/tokenUtil'
import { BatchSignedERC721Order } from './batchSignedTypes'
import { encodeBits } from '../../util/bitsUtil'
const BATCH_SIGNED_ERC721_ORDERS_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'uint256', name: 'listingTime' },
{ type: 'uint256', name: 'expiryTime' },
{ type: 'uint256', name: 'startNonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'address', name: 'platformFeeRecipient' },
{ type: 'BasicCollection[]', name: 'basicCollections' },
{ type: 'Collection[]', name: 'collections' },
{ type: 'uint256', name: 'hashNonce' }
]
const BASIC_COLLECTION_ABI = [
{ type: 'address', name: 'nftAddress' },
{ type: 'bytes32', name: 'fee' },
{ type: 'bytes32[]', name: 'items' }
]
const COLLECTION_ABI = [
{ type: 'address', name: 'nftAddress' },
{ type: 'bytes32', name: 'fee' },
{ type: 'OrderItem[]', name: 'items' }
]
const ORDER_ITEM_ABI = [
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'uint256', name: 'nftId' }
]
export function getTypedData(order: BatchSignedERC721Order, chainId: number): any {
return {
types: {
['BatchSignedERC721Orders']: BATCH_SIGNED_ERC721_ORDERS_ABI,
['BasicCollection']: BASIC_COLLECTION_ABI,
['Collection']: COLLECTION_ABI,
['OrderItem']: ORDER_ITEM_ABI
},
domain: {
name: 'ElementEx',
version: '1.0.0',
chainId: chainId,
verifyingContract: order.exchange
},
primaryType: 'BatchSignedERC721Orders',
message: toStandardOrder(order)
}
}
function toStandardOrder(order: BatchSignedERC721Order): any {
return {
maker: order.maker,
listingTime: order.listingTime,
expiryTime: encodeBits([
[ 0, 4 ],
[ order.oracleSignature, 4 ],
[ order.expirationTime, 248 ]
]),
startNonce: order.startNonce,
erc20Token: toContractERC20Token(order.paymentToken),
platformFeeRecipient: order.platformFeeRecipient,
basicCollections: toStandardBasicCollections(order),
collections: toStandardCollections(order),
hashNonce: order.hashNonce
}
}
function toStandardBasicCollections(order: BatchSignedERC721Order) {
const basicCollections: any[] = []
if (order.basicCollections != null) {
for (const collection of order.basicCollections) {
const items: string[] = []
if (collection.items) {
for (const item of collection.items) {
/// @param item [96 bits(erc20TokenAmount) + 160 bits(nftId)].
items.push(encodeBits([
[ item.erc20TokenAmount, 96 ],
[ item.nftId, 160 ]
]))
}
}
basicCollections.push({
nftAddress: collection.nftAddress,
/// @param fee [16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)].
fee: encodeBits([
[ 0, 64 ],
[ collection.platformFee, 16 ],
[ collection.royaltyFee, 16 ],
[ collection.royaltyFeeRecipient, 160 ]
]),
items: items
})
}
}
return basicCollections
}
function toStandardCollections(order: BatchSignedERC721Order) {
const collections: any[] = []
if (order.collections != null) {
for (const collection of order.collections) {
const items: any[] = []
if (collection.items) {
items.push(...collection.items)
}
collections.push({
nftAddress: collection.nftAddress,
/// @param fee [16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)].
fee: encodeBits([
[ 0, 64 ],
[ collection.platformFee, 16 ],
[ collection.royaltyFee, 16 ],
[ collection.royaltyFeeRecipient, 160 ]
]),
items: items
})
}
}
return collections
}
FILE:scripts/code/src/element/batchSignedOrder/batchSignedOrderManager.ts
import { Web3Signer } from '../../signer/Web3Signer'
import { getElementExContract, getHelperContract } from '../../contracts/contracts'
import { BigNumber, ethers } from 'ethers'
import {
AssetSchema,
ERC721SellOrderItem,
MakeERC721SellOrdersParams,
NULL_ADDRESS,
OrderInformation,
OrderSide,
SaleKind,
Standard
} from '../../types/types'
import { DEFAULT_EXPIRATION_TIME, MAX_EXPIRATION_TIME, MAX_LISTING_TIME } from '../order/orderTypes'
import { ApiOption, Fees } from '../../api/openApiTypes'
import { getChain } from '../../util/chainUtil'
import { toStandardERC20Token } from '../../util/tokenUtil'
import { BatchSignedERC721Order, BatchSignedERC721OrderRequest, Collection } from './batchSignedTypes'
import { getTypedData } from './batchSignedTypedData'
import { queryFees, queryNonce, queryOracleSignature } from '../../api/openApi'
import { toString } from '../../util/numberUtil'
export const maxBasicNftId = BigNumber.from('0xffffffffffffffffffffffffffffffffffffffff')
export const maxERC20Amount = BigNumber.from('0xffffffffffffffffffffffffffffffffffffffff')
export const maxBasicERC20Amount = BigNumber.from('0xffffffffffffffffffffffff')
export class BatchSignedOrderManager {
public web3Signer: Web3Signer
public apiOption: ApiOption
constructor(web3Signer: Web3Signer, apiOption: ApiOption) {
this.web3Signer = web3Signer
this.apiOption = apiOption
}
public async createOrders(params: MakeERC721SellOrdersParams, counter?: number): Promise<Array<BatchSignedERC721Order>> {
const fees = await this.queryFees(params)
const platformFeeRecipient = getPlatformFeeRecipient(fees)
const chain = getChain(this.web3Signer.chainId)
const maker = await this.web3Signer.getCurrentAccount()
const paymentToken = toStandardERC20Token(params.paymentToken)
const { listingTime, expirationTime } = getOrderTime(params)
const elementEx = await this.getElementEx()
const hashNonce = (counter != null) ? counter : await elementEx.getHashNonce(maker)
const list = getOrders(params.items)
const orders: BatchSignedERC721Order[] = []
let error
for (const order of list) {
try {
const nonce = await queryNonce({
maker: maker,
schema: AssetSchema.ERC721,
count: order.itemCount
}, this.apiOption)
const oracleSignature = await queryOracleSignature(this.apiOption)
setCollectionFees(order.basicCollections, fees)
setCollectionFees(order.collections, fees)
orders.push({
exchange: elementEx.address.toLowerCase(),
maker: maker.toLowerCase(),
listingTime: listingTime,
expirationTime: expirationTime,
startNonce: nonce,
paymentToken: paymentToken,
platformFeeRecipient: platformFeeRecipient,
basicCollections: order.basicCollections,
collections: order.collections,
hashNonce: hashNonce.toString(),
oracleSignature,
chain: chain
})
} catch (e) {
error = e
}
}
if (orders.length == 0) {
throw error
}
return orders
}
public async approveAndGetCounter(params: MakeERC721SellOrdersParams): Promise<number> {
checkSellOrdersParams(params)
const set: Set<string> = new Set
for (const item of params.items) {
set.add(item.erc721TokenAddress.toLowerCase())
}
const elementEx = await this.getElementEx()
const helper = await this.getHelper()
const list: any[] = []
for (const value of set.values()) {
list.push({
tokenType: 0,
tokenAddress: value,
operator: elementEx.address
})
}
const owner = await this.web3Signer.getCurrentAccount()
const r = await helper.getSDKApprovalsAndCounter(owner, list)
for (let i = 0; i < list.length; i++) {
if (r.approvals[i].eq(0)) {
console.log('start approveERC721, ERC721Address =', list[i].tokenAddress)
const tx = await this.web3Signer.approveERC721Proxy(owner, list[i].tokenAddress, elementEx.address, params)
console.log('approveERC721, tx.hash', tx.hash)
const receipt = await tx.wait(1)
console.log('approveERC721, completed receipt', JSON.stringify(receipt))
console.log('approveERC721, completed gasUsed =', toString(receipt.gasUsed))
}
}
return parseInt(r.elementCounter)
}
public async signOrder(order: BatchSignedERC721Order): Promise<BatchSignedERC721OrderRequest> {
const typedData = getTypedData(order, this.web3Signer.chainId)
const sign = await this.web3Signer.signTypedData(order.maker, typedData)
const o = order as BatchSignedERC721OrderRequest
o.v = sign.v
o.r = sign.r
o.s = sign.s
o.hash = Web3Signer.getOrderHash(typedData)
// const r = await this.helper.checkBSERC721Orders(o)
// console.log(JSON.stringify(r))
// console.log(JSON.stringify(o))
return o
}
private async getElementEx() {
const signer = await this.web3Signer.getSigner()
return getElementExContract(this.web3Signer.chainId, signer)
}
private async getHelper() {
const signer = await this.web3Signer.getSigner()
return getHelperContract(this.web3Signer.chainId, signer)
}
private async queryFees(params: MakeERC721SellOrdersParams): Promise<Map<string, Fees>> {
const addressList: string[] = []
for (const item of params.items) {
const address = item.erc721TokenAddress.toLowerCase()
if (!addressList.includes(address)) {
addressList.push(address)
}
}
const fees = await queryFees(addressList, this.apiOption)
const map: Map<string, Fees> = new Map<string, Fees>()
for (const fee of fees) {
map.set(fee.contractAddress.toLowerCase(), fee)
}
return map
}
}
export function getSucceedList(order: BatchSignedERC721OrderRequest, assets: any[]): OrderInformation[] {
if (assets.length == 0) {
return []
}
const map: Map<string, any> = new Map
let nonce = Number(order.startNonce)
for (const collection of order.basicCollections) {
for (const item of collection.items) {
const key = (collection.nftAddress + ',' + item.nftId).toLowerCase()
const value = {
erc20TokenAmount: item.erc20TokenAmount,
nonce: nonce++
}
map.set(key, value)
}
}
for (const collection of order.collections) {
for (const item of collection.items) {
const key = (collection.nftAddress + ',' + item.nftId).toLowerCase()
const value = {
erc20TokenAmount: item.erc20TokenAmount,
nonce: nonce++
}
map.set(key, value)
}
}
const list: OrderInformation[] = []
for (const asset of assets) {
const assetContract = asset.assetContract?.toString().toLowerCase() || ''
const tokenId = toString(asset.assetTokenId)
const key = assetContract + ',' + tokenId
const value = map.get(key)
if (value) {
list.push({
contractAddress: assetContract,
tokenId: tokenId,
schema: AssetSchema.ERC721,
standard: Standard.ElementEx,
maker: order.maker,
listingTime: order.listingTime,
expirationTime: order.expirationTime,
price: Number(ethers.utils.formatEther(value.erc20TokenAmount)),
paymentToken: order.paymentToken,
saleKind: SaleKind.BatchSignedERC721Order,
side: OrderSide.SellOrder,
orderId: asset.orderId
})
}
}
return list
}
function checkSellOrdersParams(params: MakeERC721SellOrdersParams) {
if (!params.items?.length) {
throw Error(`makeERC721SellOrders failed, items.length error.`)
}
const set: Set<string> = new Set<string>()
for (const item of params.items) {
const key = item.erc721TokenAddress.toLowerCase() + ',' + toString(item.erc721TokenId)
if (set.has(key)) {
throw Error(`makeERC721SellOrders failed, the same asset is not supported, assetAddress(item.erc721TokenAddress, assetId(item.erc721TokenId)).`)
}
set.add(key)
}
}
function setCollectionFees(collections: Collection[], fees: Map<String, Fees>) {
for (const collection of collections) {
const fee = fees.get(collection.nftAddress)
if (fee) {
if (fee.protocolFeeAddress && fee.protocolFeeAddress.toLowerCase() != NULL_ADDRESS) {
collection.platformFee = fee.protocolFeePoints || 0
}
if (fee.royaltyFeeAddress && fee.royaltyFeeAddress.toLowerCase() != NULL_ADDRESS) {
collection.royaltyFee = fee.royaltyFeePoints || 0
collection.royaltyFeeRecipient = fee.royaltyFeeAddress.toLowerCase()
}
}
if (collection.platformFee < 0 || collection.royaltyFee < 0 || (collection.platformFee + collection.royaltyFee) > 10000) {
throw Error(`makeERC721SellOrders failed, feePoint error, platformFeePoint(collection.platformFee, royaltyFeePoint(collection.royaltyFee)`)
}
}
}
function getPlatformFeeRecipient(fees: Map<String, Fees>): string {
let platformFeeRecipient
for (const fee of fees.values()) {
if (fee.protocolFeePoints) {
const protocolFeeAddress = fee.protocolFeeAddress ? fee.protocolFeeAddress.toLowerCase() : NULL_ADDRESS
if (platformFeeRecipient) {
if (platformFeeRecipient != protocolFeeAddress) {
throw Error(`check platformFeeRecipient failed, platformFeeRecipient1(platformFeeRecipient), platformFeeRecipient2(protocolFeeAddress)`)
}
} else {
platformFeeRecipient = protocolFeeAddress
}
}
}
return platformFeeRecipient ? platformFeeRecipient : NULL_ADDRESS
}
function getOrders(items: ERC721SellOrderItem[]): any[] {
const map: Map<string, any> = new Map
for (const item of items) {
if (!item.erc721TokenAddress || item.erc721TokenAddress.toLowerCase() == NULL_ADDRESS) {
throw Error(`makeERC721SellOrders failed, tokenAddress(item.erc721TokenAddress) error.`)
}
if (item.erc721TokenId == null || item.erc721TokenId === '') {
throw Error(`makeERC721SellOrders failed, tokenId(item.erc721TokenId) error.`)
}
let collection = map.get(item.erc721TokenAddress.toLowerCase())
if (collection == null) {
collection = {
nftAddress: item.erc721TokenAddress.toLowerCase(),
items: [],
isBasic: true
}
map.set(collection.nftAddress, collection)
}
const obj = {
erc20TokenAmount: toString(item.paymentTokenAmount),
nftId: toString(item.erc721TokenId)
}
collection.items.push(obj)
if (collection.isBasic) {
if (maxBasicERC20Amount.lt(obj.erc20TokenAmount) || maxBasicNftId.lt(obj.nftId)) {
collection.isBasic = false
}
}
if (maxERC20Amount.lt(obj.erc20TokenAmount)) {
throw Error(`makeERC721SellOrders failed, item.paymentTokenAmount(obj.erc20TokenAmount exceed the maxValue(maxERC20Amount.toHexString())).`)
}
}
let point = 0
let order: any = null
const orders: any[] = []
for (const value of map.values()) {
if (isOrderFulled(point, 2, order)) {
point = 0
order = null
}
point += 2
let collection
const plusPoint = value.isBasic ? 1 : 2
for (const item of value.items) {
if (isOrderFulled(point, plusPoint, order)) {
point = 2
order = null
collection = null
}
if (order == null) {
order = {
basicCollections: [],
collections: [],
itemCount: 0
}
orders.push(order)
}
if (collection == null) {
collection = {
nftAddress: value.nftAddress,
platformFee: 0,
royaltyFeeRecipient: NULL_ADDRESS,
royaltyFee: 0,
items: []
}
if (value.isBasic) {
order.basicCollections.push(collection)
} else {
order.collections.push(collection)
}
}
point += plusPoint
order.itemCount++
collection.items.push(item)
}
}
return orders
}
function isOrderFulled(point: number, plusPoint: number, order: any) {
if (point + plusPoint > 102) {
return true
}
return order != null && order.itemCount >= 50
}
function getOrderTime(params: MakeERC721SellOrdersParams) {
const now = Math.floor(Date.now() / 1000)
let listingTime
if (params.listingTime) {
listingTime = params.listingTime
if (listingTime > now + MAX_LISTING_TIME) {
throw Error('makeERC721SellOrders failed, require listingTime <= now + 1 year.')
}
if (listingTime < (now - 1800)) {
throw Error('makeERC721SellOrders failed, listingTime >= now - 30 minute.')
}
} else {
listingTime = now - 60
}
let expirationTime
if (params.expirationTime != null) {
expirationTime = params.expirationTime
if (expirationTime < Math.max(listingTime, now)) {
throw Error('makeERC721SellOrders failed, require expirationTime >= Math.max(listingTime, now).')
}
if (expirationTime > Math.max(listingTime, now) + MAX_EXPIRATION_TIME) {
throw Error('makeERC721SellOrders failed, require expirationTime <= Math.max(listingTime, now) + 1 year.')
}
} else {
expirationTime = Math.max(listingTime, now) + DEFAULT_EXPIRATION_TIME
}
return { listingTime, expirationTime }
}
FILE:scripts/code/src/api/openApiTypes.ts
import { OrderSide, SaleKind } from "../types/types";
export const API_HOST = "https://api.element.market";
export const TIME_OUT = 15000;
export interface ApiOption {
chain: string;
isTestnet: boolean;
apiKey: string;
}
export interface NonceQuery {
// The order maker's wallet address
maker: string;
// Schema eg. erc721, erc1155
schema: string;
// The number of nonces occupied this time, The default is 1.
// for example: count is 5, and the returned data is 4, then
// the nonce equivalent to [4,4+5-1] is this request.
count: number;
}
export interface Fees {
contractAddress: string;
protocolFeePoints: number;
protocolFeeAddress: string;
royaltyFeePoints: number;
royaltyFeeAddress: string;
}
export interface OrderQuery {
// Filter by smart contract address for the asset category.
asset_contract_address?: string;
// Filter by a list of token IDs for the order's asset, comma separated. Needs to be defined together with asset_contract_address.
token_ids?: Array<string | number>;
// Filter by the kind of sell order. 0 for fixed-price sales, 1 for declining-price Dutch Auctions, 2 for English Auctions
sale_kind?: SaleKind;
// Filter by the side of the order. 0 for buy orders and 1 for sell orders.
side?: OrderSide;
// Filter by the order maker's wallet address
maker?: string;
// Filter by the order maker's wallet address
taker?: string;
// Filter by the address of the smart contract of the payment token that is accepted
// or offered by the order, Eth and other primary chain currencies are 0x0000000000000000000000000000000000000000
payment_token?: string;
// How to sort the orders. Can be `created_date` for when they were made,
// or `base_price` to see the lowest-priced orders first.
// when using 1created_date1, the results are sorted by listingTime.
// use with direction, created_date is default.
order_by?: string;
// Can be asc or desc for ascending or descending sort. Default value : desc
direction?: string;
// Only show orders listed before this timestamp. Seconds since the Unix epoch.
listed_before?: number | string;
// Only show orders listed after this timestamp. Seconds since the Unix epoch.
listed_after?: number | string;
// Number of orders to return (capped at 50, default is 20). Default value: 20
limit?: number;
// Number of orders to offset by (for pagination). Default value: 0
offset?: number;
}
export interface QueryAccountOrdersParams {
// Wallet address (defaults to account address if empty).
wallet_address?: string;
// Contract address.
contract_address?: string;
// Cursor to retrieve the next page of assets
cursor?: string;
// Page size, max is 50, default 20
limit?: number | string;
}
export interface AccountOrderPageInfo {
startCursor?: string;
endCursor?: string;
hasPreviousPage?: string | boolean;
hasNextPage?: string | boolean;
}
export interface AccountOrderCollection {
name?: string;
slug?: string;
royalty?: number;
imageUrl?: string;
isVerified?: boolean;
}
export interface AccountOrderAsset {
chain?: string;
chainId?: string;
contractAddress?: string;
tokenId?: string;
name?: string;
supply?: number | string;
imagePreviewUrl?: string;
collection?: AccountOrderCollection;
}
export interface AccountOrderSummary {
chain?: string;
chainId?: string;
expirationTime?: number | string;
listingTime?: number | string;
maker?: string;
taker?: string;
side?: number | string;
saleKind?: number | string;
paymentToken?: string;
quantity?: string;
priceUSD?: number | string;
price?: number | string;
standard?: string;
contractAddress?: string;
tokenId?: string;
schema?: string;
extra?: string;
}
export interface AccountOrderListItem {
cursor?: string;
asset?: AccountOrderAsset;
orderData?: {
accountOrder?: AccountOrderSummary;
};
}
export interface QueryAccountOrdersResponseData {
pageInfo?: AccountOrderPageInfo;
assetList?: Array<AccountOrderListItem>;
}
FILE:scripts/code/src/api/openApi.ts
import axios from "axios";
import { OrderRequest } from "../element/order/orderTypes";
import {
QueryAccountOrdersParams,
QueryAccountOrdersResponseData,
API_HOST,
ApiOption,
Fees,
NonceQuery,
OrderQuery,
TIME_OUT,
} from "./openApiTypes";
import { Order } from "../types/types";
import { BatchSignedERC721OrderRequest } from "../element/batchSignedOrder/batchSignedTypes";
const instance = axios.create();
export async function postOrder(
order: OrderRequest,
option: ApiOption,
retries = 1,
) {
let r;
try {
console.log("Wait for postOrder.");
r = await instance({
method: "post",
url: toUrl("/openapi/v1/orders/post", option),
headers: { "x-api-key": option.apiKey },
data: order,
timeout: TIME_OUT,
});
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("postOrder failed, " + e + ", now try again.");
await sleep(1000);
return postOrder(order, option, retries - 1);
}
throw Error(`postOrder failed, e, order: JSON.stringify(order)`);
}
if (r.data?.code !== 0) {
throw Error(
`postOrder failed, r.data?.code, r.data?.msg, JSON.stringify(order)`,
);
}
console.log("postOrder completed.");
return r.data.data;
}
export async function postBatchSignedERC721SellOrder(
order: BatchSignedERC721OrderRequest,
option: ApiOption,
retries = 1,
): Promise<any> {
let r;
try {
console.log("Wait for postBatchOrder.");
r = await instance({
method: "post",
url: toUrl("/openapi/v1/orders/postBatch", option),
headers: { "x-api-key": option.apiKey },
data: order,
timeout: TIME_OUT,
});
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("postBatchOrder failed, " + e + ", now try again.");
await sleep(1000);
return postBatchSignedERC721SellOrder(order, option, retries - 1);
}
throw Error(`postBatchOrder failed, e, order: order`);
}
if (r.data?.code === 0 && r.data?.data) {
console.log("postBatchOrder completed.");
return {
successList: r.data.data.successList || [],
failList: r.data.data.failList || [],
};
}
throw Error(
`postBatchOrder failed, r.data?.code, r.data?.msg, JSON.stringify(order)`,
);
}
export async function queryTradeData(
account: string,
list: Array<{
orderId: String;
takeCount: number;
tokenId?: string;
}>,
option: ApiOption,
retries = 1,
): Promise<any> {
let r;
try {
r = await instance({
method: "post",
url: toUrl("/openapi/v1/orders/encodeTradeDataByOrderId", option),
headers: { "x-api-key": option.apiKey },
data: {
chain: option.chain,
taker: account.toLowerCase(),
orderIdList: list,
},
timeout: TIME_OUT,
});
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("encodeTradeData failed, " + e + ", now try again.");
await sleep(1000);
return queryTradeData(account, list, option, retries - 1);
}
throw Error(`encodeTradeData failed, e`);
}
if (r.data?.code === 0 && r.data?.data) {
return r.data?.data;
}
throw Error(`encodeTradeData failed, r.data?.code, r.data?.msg`);
}
export async function queryNonce(
query: NonceQuery,
option: ApiOption,
retries = 1,
): Promise<number> {
let r;
try {
const url =
toUrl(`/openapi/v1/orders/nonce?chain=option.chain`, option) +
toKeyVal("maker", query) +
toKeyVal("exchange", query) +
toKeyVal("schema", query) +
toKeyVal("count", query);
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: TIME_OUT,
});
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryNonce failed, " + e + ", now try again.");
await sleep(1000);
return queryNonce(query, option, retries - 1);
}
throw Error("queryNonce failed, " + e);
}
if (r.data?.code === 0 && r.data?.data?.nonce != null) {
console.log("queryNonce, nonce: " + r.data.data.nonce.toString());
return Number(r.data.data.nonce.toString());
}
throw Error("queryNonce failed, " + r.data?.msg);
}
export async function queryOracleSignature(
option: ApiOption,
retries = 1,
): Promise<number> {
let r;
try {
const url = toUrl(
`/openapi/v1/orders/confData?chain=option.chain`,
option,
);
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: TIME_OUT,
});
if (r.data?.data?.oracleSignature != null) {
console.log(
"queryOracleSignature success, oracleSignature: " +
r.data.data.oracleSignature,
);
return Number(r.data.data.oracleSignature);
}
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryOracleSignature failed, " + e + ", now try again.");
await sleep(1000);
return queryOracleSignature(option, retries - 1);
}
}
console.log("queryOracleSignature failed, use default value `0`");
return 0;
}
export async function queryFees(
contractAddressList: string[],
option: ApiOption,
retries = 1,
): Promise<Array<Fees>> {
let r;
try {
r = await instance({
method: "post",
url: toUrl("/openapi/v1/collection/fee", option),
headers: { "x-api-key": option.apiKey },
data: {
chain: option.chain,
data: contractAddressList.map((value) => {
return {
contractAddress: value.toLowerCase(),
};
}),
},
timeout: TIME_OUT,
});
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryFees failed, " + e + ", now try again.");
await sleep(1000);
return queryFees(contractAddressList, option, retries - 1);
}
throw Error("queryFees failed, " + e);
}
if (r.data?.code === 0) {
return r.data?.data?.feeList || [];
}
throw Error("queryFees failed, " + r.data?.msg);
}
export async function queryOrders(
query: OrderQuery,
option: ApiOption,
): Promise<Array<Order>> {
const url =
toUrl(`/openapi/v1/orders/list?chain=option.chain`, option) +
toKeyVal("asset_contract_address", query) +
toTokenIdsKeyVal("token_ids", query) +
toKeyVal("sale_kind", query) +
toKeyVal("side", query) +
toKeyVal("maker", query) +
toKeyVal("taker", query) +
toKeyVal("payment_token", query) +
toKeyVal("order_by", query) +
toKeyVal("direction", query) +
toKeyVal("listed_before", query) +
toKeyVal("listed_after", query) +
toKeyVal("limit", query) +
toKeyVal("offset", query);
let r;
try {
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: TIME_OUT,
});
} catch (e) {
throw Error("queryOrders failed, " + e);
}
if (r.data?.code === 0) {
return r.data?.data?.orders || [];
}
throw Error("queryOrders failed, " + r.data?.msg);
}
export async function queryAccountOrders(
query: QueryAccountOrdersParams,
option: ApiOption,
retries = 1,
): Promise<QueryAccountOrdersResponseData> {
const chain = option.chain;
const normalizedLimit = Number(query.limit ?? 20);
const safeLimit =
Number.isFinite(normalizedLimit) && normalizedLimit > 0
? Math.min(normalizedLimit, 50)
: 20;
const url =
toUrl(`/openapi/v1/account/orderList?chain=chain`, option) +
toKeyVal("wallet_address", query) +
toKeyVal("contract_address", query) +
toKeyVal("cursor", query) +
`&limit=safeLimit`;
let r;
try {
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: TIME_OUT,
});
} catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryAccountOrders failed, " + e + ", now try again.");
await sleep(1000);
return queryAccountOrders(query, option, retries - 1);
}
throw Error("queryAccountOrders failed, " + e);
}
if (r.data?.code === 0) {
return r.data?.data || {};
}
throw Error("queryAccountOrders failed, " + r.data?.msg);
}
function toUrl(path: string, option: ApiOption): string {
return API_HOST + path;
}
function sleep(ms: number) {
return Promise.resolve((resolve: () => void) => setTimeout(resolve, ms));
}
function toTokenIdsKeyVal(key: string, query: any): string {
let val = "";
if (query[key]?.length) {
for (const id of query[key]) {
const idStr = formatVal(id);
if (idStr != "") {
if (val != "") {
val += ",";
}
val += idStr;
}
}
}
return val != "" ? `&key=val` : "";
}
function toKeyVal(key: string, query: any): string {
const val = formatVal(query[key]);
return val != "" ? `&key=val` : "";
}
function formatVal(value: any): string {
return value != null ? value.toString().toLowerCase() : "";
}
function shouldRetry(error: any, retries: number): boolean {
if (retries > 0) {
if (error?.message?.toString().startsWith("timeout of")) {
return true;
}
if (error?.response) {
const status = error?.response.status;
return (
status == 403 ||
status == 429 ||
status == 500 ||
status == 502 ||
status == 503 ||
status == 504
);
}
}
return false;
}
FILE:scripts/code/src/index.ts
import { getChainId } from "./util/chainUtil";
import {
postBatchSignedERC721SellOrder,
postOrder,
queryFees,
queryAccountOrders,
queryNonce,
queryOracleSignature,
queryOrders,
queryTradeData,
} from "./api/openApi";
import {
TransactionReceipt,
TransactionResponse,
} from "@ethersproject/abstract-provider";
import {
Asset,
AssetSchema,
BatchBuyWithETHParams,
CancelAllOrdersByMakerParams,
CancelOrderParams,
CancelOrdersParams,
CancelOrdersResponse,
CancelOrdersTransaction,
ElementAPIConfig,
EncodeTradeDataParams,
FailedERC721Item,
FillOrderParams,
MakeERC721SellOrdersParams,
MakeERC721SellOrdersResponse,
MakeOrderParams,
NULL_ADDRESS,
Order,
OrderInformation,
OrderSide,
SaleKind,
Standard,
TradeData,
} from "./types/types";
import { LimitedCallSpec, Web3Signer } from "./signer/Web3Signer";
import {
BatchSignedOrderManager,
getSucceedList,
} from "./element/batchSignedOrder/batchSignedOrderManager";
import { OrderManager } from "./element/order/orderManager";
import { ApiOption, OrderQuery, QueryAccountOrdersParams, QueryAccountOrdersResponseData } from "./api/openApiTypes";
import { CreateOrderParams } from "./element/order/orderTypes";
import {
toOrderInformation,
toOrderRequest,
} from "./element/order/orderConverter";
import { toNumber, toString } from "./util/numberUtil";
import { getBoughtAssets } from "./util/receiptUtil";
import {
approveERC20,
setApproveForAll,
transferERC721,
transferERC1155,
} from "./util/assetUtil";
import { ethers } from "ethers";
import { toStandardERC20Token } from "./util/tokenUtil";
import { log } from "console";
export class ElementSDK {
public chainId: number;
public apiOption: ApiOption;
public web3Signer: Web3Signer;
public batchOrderManager: BatchSignedOrderManager;
public orderManager: OrderManager;
public isTestnet: boolean = false;
constructor(config: ElementAPIConfig) {
if (config.isTestnet != null) {
this.isTestnet = config.isTestnet;
}
this.chainId = getChainId(config.networkName, this.isTestnet);
this.apiOption = {
chain: config.networkName,
isTestnet: this.isTestnet,
apiKey: config.apiKey,
};
this.web3Signer = new Web3Signer(config.signer, this.chainId);
this.batchOrderManager = new BatchSignedOrderManager(
this.web3Signer,
this.apiOption,
);
this.orderManager = new OrderManager(this.web3Signer);
}
public async makeERC721SellOrders(
params: MakeERC721SellOrdersParams,
): Promise<MakeERC721SellOrdersResponse> {
let error;
const succeedList: OrderInformation[] = [];
const failedList: FailedERC721Item[] = [];
// 1. setApproveForAll
const counter = await this.batchOrderManager.approveAndGetCounter(params);
// 2. create orders
const orders = await this.batchOrderManager.createOrders(params, counter);
for (const order of orders) {
try {
// 3. sign order
const signedOrder = await this.batchOrderManager.signOrder(order);
// 4. post order
const r = await postBatchSignedERC721SellOrder(
signedOrder,
this.apiOption,
);
succeedList.push(...getSucceedList(signedOrder, r.successList));
failedList.push(...r.failList);
} catch (e) {
error = e;
}
}
if (succeedList.length == 0 && failedList.length == 0) {
throw error;
}
return {
succeedList: succeedList,
failedList: failedList,
};
}
public async makeSellOrder(
params: MakeOrderParams,
): Promise<OrderInformation> {
if (params.assetId == null) {
throw Error("createSellOrder failed, asset.id is undefined.");
}
if (
(!params.assetSchema || params.assetSchema.toLowerCase() == "erc721") &&
(!params.takerAddress ||
params.takerAddress.toLowerCase() == NULL_ADDRESS)
) {
const r = await this.makeERC721SellOrders({
listingTime: params.listingTime,
expirationTime: params.expirationTime,
paymentToken: params.paymentToken,
items: [
{
erc721TokenId: toString(params.assetId),
erc721TokenAddress: params.assetAddress,
paymentTokenAmount: toString(params.paymentTokenAmount),
},
],
gasPrice: params.gasPrice,
maxFeePerGas: params.maxFeePerGas,
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
});
if (!r.succeedList?.length) {
const e = r.failedList?.length ? r.failedList[0].errorDetail : "";
throw Error("createSellOrder failed, " + e);
}
return r.succeedList[0];
}
return await this.makeOrder(params, false);
}
public async makeBuyOrder(
params: MakeOrderParams,
): Promise<OrderInformation> {
return await this.makeOrder(params, true);
}
public async fillOrder(
params: FillOrderParams,
): Promise<TransactionResponse> {
if (params.order.standard?.toString().toLowerCase() != Standard.ElementEx) {
throw Error(
`fillOrder failed, standard(params.order.standard) is not supported`,
);
}
const account = await this.web3Signer.getCurrentAccount();
const takeCount = params.quantity ? Number(params.quantity) || 1 : 1;
if (
params.order.side === OrderSide.SellOrder ||
params.order.side == "sell"
) {
if (toStandardERC20Token(params.order.paymentToken) !== NULL_ADDRESS) {
const providedDecimals = Number(params.order.paymentTokenDecimals);
if (!Number.isFinite(providedDecimals)) {
throw Error(
"fillOrder failed, ERC20-priced orders require `paymentTokenDecimals`. Look it up from the payment token reference and pass it explicitly.",
);
}
const decimals = providedDecimals;
const payValue = takeCount * Number(params.order.price);
const value = ethers.utils.parseUnits(payValue.toString(), decimals);
console.log(
"approve: " + JSON.stringify(params),
JSON.stringify(value),
);
await approveERC20(
this.web3Signer,
params.order.paymentToken,
value,
params,
);
}
} else {
await setApproveForAll(
this.web3Signer,
params.order.contractAddress,
params,
);
}
if (
params.order.saleKind === SaleKind.ContractOffer ||
params.order.saleKind === SaleKind.BatchOfferERC721s
) {
if (!params.assetId?.toString()) {
throw Error(
`fillOrder failed, Collection-Based Offer requires the \`assetId\`.`,
);
}
}
const tradeData = await queryTradeData(
account,
[
{
orderId: params.order.orderId,
takeCount,
tokenId: params.assetId?.toString(),
},
],
this.apiOption,
);
const call: LimitedCallSpec = {
from: account,
to: tradeData.to,
value: tradeData.value,
data: tradeData.data,
gasPrice: params.gasPrice,
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
maxFeePerGas: params.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
public async batchBuyWithETH(
params: BatchBuyWithETHParams,
): Promise<TransactionResponse> {
const taker = await this.web3Signer.getCurrentAccount();
const list = this.toOrderIdList(params.orders, params.quantities);
const tradeData = await queryTradeData(taker, list, this.apiOption);
const call: LimitedCallSpec = {
from: taker,
to: tradeData.to,
value: tradeData.value,
data: tradeData.data,
gasPrice: params.gasPrice,
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
maxFeePerGas: params.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
public async encodeTradeData(
params: EncodeTradeDataParams,
): Promise<TradeData> {
let taker = params.taker;
if (taker == null || taker == "" || taker.toLowerCase() == NULL_ADDRESS) {
taker = await this.web3Signer.getCurrentAccount();
}
const list = this.toOrderIdList(
params.orders,
params.quantities,
params.tokenIds,
);
const tradeData = await queryTradeData(taker, list, this.apiOption);
return {
toContract: tradeData.to,
payableValue: tradeData.value,
data: tradeData.data,
flags: tradeData.flags,
};
}
public getBoughtAssets(receipt: TransactionReceipt): Array<Asset> {
return getBoughtAssets(receipt);
}
public async cancelOrder(
params: CancelOrderParams,
): Promise<TransactionResponse> {
const account = await this.web3Signer.getCurrentAccount();
if (params.order?.maker?.toLowerCase() != account.toLowerCase()) {
throw Error(
`cancelOrder failed, account mismatch, order.maker(params.order?.maker), account(account).`,
);
}
const signedOrder = JSON.parse(params.order.exchangeData);
if (params.order.standard?.toString().toLowerCase() == Standard.ElementEx) {
if (
params.order.schema.toLowerCase() == AssetSchema.ERC721.toLowerCase()
) {
return this.orderManager.cancelERC721Orders([signedOrder], params);
} else if (
params.order.schema.toLowerCase() == AssetSchema.ERC1155.toLowerCase()
) {
return this.orderManager.cancelERC1155Orders([signedOrder], params);
} else {
throw Error(
"cancelOrder failed, unsupported schema : " + params.order.schema,
);
}
} else {
throw Error(
"cancelOrder failed, unsupported standard : " + params.order.standard,
);
}
}
public async cancelOrders(
params: CancelOrdersParams,
): Promise<CancelOrdersResponse> {
if (!params.orders?.length) {
throw Error(`cancelOrders failed, orders?.length error.`);
}
const account = await this.web3Signer.getCurrentAccount();
params.orders.forEach((value, index, array) => {
if (account.toLowerCase() != value.maker?.toLowerCase()) {
throw Error(
`cancelOrders failed, account mismatch, index=(index), order.maker(value.maker), account(account).`,
);
}
});
const elementERC721Orders: Order[] = [];
const elementERC1155Orders: Order[] = [];
const elementERC721SignedOrders: any[] = [];
const elementERC1155SignedOrders: any[] = [];
for (const order of params.orders) {
if (order.exchangeData && order.standard) {
const signedOrder = JSON.parse(order.exchangeData);
if (order.standard.toLowerCase() == Standard.ElementEx) {
if (order.schema?.toLowerCase() == AssetSchema.ERC721.toLowerCase()) {
elementERC721Orders.push(order);
elementERC721SignedOrders.push(signedOrder);
} else if (
order.schema?.toLowerCase() == AssetSchema.ERC1155.toLowerCase()
) {
elementERC1155Orders.push(order);
elementERC1155SignedOrders.push(signedOrder);
}
}
}
}
const succeedTransactions: Array<CancelOrdersTransaction> = [];
if (elementERC721Orders.length > 0) {
const tx = await this.orderManager.cancelERC721Orders(
elementERC721SignedOrders,
params,
);
succeedTransactions.push({
orders: elementERC721Orders,
transaction: tx,
});
}
if (elementERC1155Orders.length > 0) {
try {
const tx = await this.orderManager.cancelERC1155Orders(
elementERC1155SignedOrders,
params,
);
succeedTransactions.push({
orders: elementERC1155Orders,
transaction: tx,
});
} catch (e) {
if (succeedTransactions.length == 0) {
throw e;
}
}
}
if (succeedTransactions.length == 0) {
throw Error("cancelOrders failed.");
}
return { succeedTransactions: succeedTransactions };
}
public async cancelAllOrdersForSigner(
params?: CancelAllOrdersByMakerParams,
): Promise<TransactionResponse> {
if (
params?.standard?.toLowerCase() == Standard.ElementEx ||
!params?.standard
) {
return this.orderManager.cancelAllOrders(params);
} else {
throw Error(`cancelAllOrders failed`);
}
}
public async queryOrders(query: OrderQuery): Promise<Array<Order>> {
return await queryOrders(query, this.apiOption);
}
public async queryAccountOrders(
query: QueryAccountOrdersParams,
): Promise<QueryAccountOrdersResponseData> {
return await queryAccountOrders(query, this.apiOption);
}
private toOrderIdList(
orders: Array<OrderInformation>,
quantities?: Array<string | number>,
tokenIds?: Array<string | number>,
) {
const list: any[] = [];
for (let i = 0; i < orders.length; i++) {
let takeCount = 1;
if (quantities?.length && i < quantities?.length) {
takeCount = Number(quantities[i]) || 1;
}
let tokenId;
if (tokenIds?.length && i < tokenIds.length) {
tokenId = tokenIds[i]?.toString();
} else {
if (
orders[i].saleKind === SaleKind.ContractOffer ||
orders[i].saleKind === SaleKind.BatchOfferERC721s
) {
throw Error(
`orders[i] error, the collection-based offer requires the \`assetId\``,
);
}
}
list.push({
orderId: orders[i].orderId,
takeCount,
tokenId,
});
}
return list;
}
private async makeOrder(
params: MakeOrderParams,
isBuyOrder: boolean,
): Promise<OrderInformation> {
const schema = params.assetSchema || AssetSchema.ERC721;
if (schema.toLowerCase() != "erc721" && schema.toLowerCase() != "erc1155") {
throw Error("makeOrder failed, unsupported schema : " + schema);
}
const assetId = toString(params.assetId) || undefined;
const accountAddress = await this.web3Signer.getCurrentAccount();
const takerAddress = params.takerAddress
? params.takerAddress.toLowerCase()
: NULL_ADDRESS;
// 1. query nonce
const nonce = await queryNonce(
{
maker: accountAddress,
schema: schema,
count: 1,
},
this.apiOption,
);
// 2. query oracleSignature flag
const oracleSignature = await queryOracleSignature(this.apiOption);
// 3. queryFees
let platformFeePoint,
platformFeeAddress,
royaltyFeePoint,
royaltyFeeAddress;
if (takerAddress === NULL_ADDRESS) {
const fees = await queryFees([params.assetAddress], this.apiOption);
if (fees.length > 0) {
platformFeePoint = fees[0].protocolFeePoints;
platformFeeAddress = fees[0].protocolFeeAddress;
royaltyFeePoint = fees[0].royaltyFeePoints;
royaltyFeeAddress = fees[0].royaltyFeeAddress;
}
}
// 4. create order
const quantity =
params.quantity != null ? toString(params.quantity) : undefined;
const orderParams: CreateOrderParams = {
makerAddress: accountAddress,
takerAddress,
asset: {
id: assetId,
address: params.assetAddress,
schema: schema.toString().toUpperCase(),
},
quantity: quantity,
paymentToken: params.paymentToken,
startTokenAmount: toString(params.paymentTokenAmount),
platformFeePoint: platformFeePoint ?? 0,
platformFeeAddress: platformFeeAddress,
royaltyFeePoint: royaltyFeePoint ?? 0,
royaltyFeeAddress: royaltyFeeAddress,
listingTime: toNumber(params.listingTime),
expirationTime: toNumber(params.expirationTime),
nonce: nonce.toString(),
saleKind: SaleKind.FixedPrice,
oracleSignature,
};
const order = isBuyOrder
? await this.orderManager.createBuyOrder(orderParams, params)
: await this.orderManager.createSellOrder(orderParams, params);
console.log(order);
// 4. sign order
const signedOrder = await this.orderManager.signOrder(order);
// 5. post order
const request = toOrderRequest(signedOrder);
const response = await postOrder(request, this.apiOption);
return toOrderInformation(request, response.orderId);
}
public async transferERC721(
tokenAddress: string,
tokenId: string,
toAddress: string,
): Promise<TransactionReceipt> {
return transferERC721(this.web3Signer, tokenAddress, tokenId, toAddress);
}
public async transferERC1155(
tokenAddress: string,
tokenId: string,
toAddress: string,
quantity: string,
): Promise<TransactionReceipt> {
return transferERC1155(
this.web3Signer,
tokenAddress,
tokenId,
toAddress,
quantity,
);
}
}
FILE:scripts/package.json
{
"name": "element-nft-trader",
"version": "1.0.0",
"description": "Element NFT Trader",
"main": "lib/entry.js",
"bin": {
"element-trade": "./lib/entry.js"
},
"scripts": {
"build": "tsc",
"start": "node lib/entry.js",
"prune:lib": "find lib -type f \\( -name '*.d.ts' -o -name '*.d.ts.map' -o -name '*.js.map' \\) -delete"
},
"dependencies": {
"ethers": "^5.7.2",
"axios": "^0.27.2"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0",
"axios-logger": "^2.8.1"
}
}
FILE:scripts/lib/code/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRpcUrlFromRemote = exports.getChainMId = exports.getChainId = exports.getChain = exports.Market = exports.Standard = exports.SaleKind = exports.OrderSide = exports.Network = exports.ETH_TOKEN_ADDRESS = exports.NULL_ADDRESS = exports.BigNumber = exports.Signer = exports.providers = exports.ethers = exports.ElementSDK = void 0;
var index_1 = require("./src/index");
Object.defineProperty(exports, "ElementSDK", { enumerable: true, get: function () { return index_1.ElementSDK; } });
var ethers_1 = require("ethers");
Object.defineProperty(exports, "ethers", { enumerable: true, get: function () { return ethers_1.ethers; } });
Object.defineProperty(exports, "providers", { enumerable: true, get: function () { return ethers_1.providers; } });
Object.defineProperty(exports, "Signer", { enumerable: true, get: function () { return ethers_1.Signer; } });
Object.defineProperty(exports, "BigNumber", { enumerable: true, get: function () { return ethers_1.BigNumber; } });
var types_1 = require("./src/types/types");
Object.defineProperty(exports, "NULL_ADDRESS", { enumerable: true, get: function () { return types_1.NULL_ADDRESS; } });
Object.defineProperty(exports, "ETH_TOKEN_ADDRESS", { enumerable: true, get: function () { return types_1.ETH_TOKEN_ADDRESS; } });
Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return types_1.Network; } });
Object.defineProperty(exports, "OrderSide", { enumerable: true, get: function () { return types_1.OrderSide; } });
Object.defineProperty(exports, "SaleKind", { enumerable: true, get: function () { return types_1.SaleKind; } });
Object.defineProperty(exports, "Standard", { enumerable: true, get: function () { return types_1.Standard; } });
Object.defineProperty(exports, "Market", { enumerable: true, get: function () { return types_1.Market; } });
var chainUtil_1 = require("./src/util/chainUtil");
Object.defineProperty(exports, "getChain", { enumerable: true, get: function () { return chainUtil_1.getChain; } });
Object.defineProperty(exports, "getChainId", { enumerable: true, get: function () { return chainUtil_1.getChainId; } });
Object.defineProperty(exports, "getChainMId", { enumerable: true, get: function () { return chainUtil_1.getChainMId; } });
var config_1 = require("./src/contracts/config");
Object.defineProperty(exports, "getRpcUrlFromRemote", { enumerable: true, get: function () { return config_1.getRpcUrlFromRemote; } });
//# sourceMappingURL=index.js.map
FILE:scripts/lib/code/src/signer/Web3Signer.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Web3Signer = void 0;
const ethers_1 = require("ethers");
const abi_1 = require("../contracts/abi");
const types_1 = require("../types/types");
const utils_1 = require("ethers/lib/utils");
const gasUtil_1 = require("../util/gasUtil");
const erc20Contract = new ethers_1.ethers.Contract(types_1.NULL_ADDRESS, abi_1.ContractABI.erc20.abi);
const erc721Contract = new ethers_1.ethers.Contract(types_1.NULL_ADDRESS, abi_1.ContractABI.erc721.abi);
const erc1155Contract = new ethers_1.ethers.Contract(types_1.NULL_ADDRESS, abi_1.ContractABI.erc1155.abi);
class Web3Signer {
constructor(signer, chainId) {
if (signer instanceof ethers_1.Signer) {
if (!signer.provider) {
throw Error('signer.provider is unset');
}
}
this.signer = signer;
this.chainId = chainId;
}
static getOrderHash(typedData) {
return utils_1._TypedDataEncoder.hash(typedData.domain, typedData.types, typedData.message);
}
async signTypedData(account, typedData) {
const signer = await this.getSigner(account);
const typedDataSigner = signer;
if (typedDataSigner._signTypedData) {
const typeSignStr = await typedDataSigner._signTypedData(typedData.domain, typedData.types, typedData.message);
const signer = ethers_1.ethers.utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, typeSignStr);
if (account.toLowerCase() !== signer.toLowerCase()) {
throw Error(`signTypedData failed, account : account, signer = signer`);
}
return ethers_1.ethers.utils.splitSignature(typeSignStr);
}
else {
throw Error('Unsupported signTypedData');
}
}
async ethSend(call) {
const transactionRequest = {
from: call.from,
to: call.to,
data: call.data
};
if (call.value && ethers_1.ethers.BigNumber.from(call.value).gt(0)) {
transactionRequest.value = ethers_1.ethers.BigNumber.from(call.value);
}
const signer = await this.getSigner(call.from);
if (call.maxFeePerGas && call.maxPriorityFeePerGas) {
transactionRequest.maxFeePerGas = ethers_1.ethers.BigNumber.from(call.maxFeePerGas);
transactionRequest.maxPriorityFeePerGas = ethers_1.ethers.BigNumber.from(call.maxPriorityFeePerGas);
}
else if (call.gasPrice) {
transactionRequest.gasPrice = ethers_1.ethers.BigNumber.from(call.gasPrice);
}
else {
if (!(this.signer instanceof ethers_1.ethers.providers.Web3Provider)) {
const gas = await (0, gasUtil_1.estimateGas)(this.chainId);
if (gas) {
transactionRequest.maxFeePerGas = gas.maxFeePerGas;
transactionRequest.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
}
}
}
// Use provided gas limit if specified, otherwise let provider estimate
if (call.gas) {
transactionRequest.gasLimit = ethers_1.ethers.BigNumber.from(call.gas);
}
return await signer.sendTransaction(transactionRequest);
}
async getSigner(account) {
let signer;
if (this.signer instanceof ethers_1.ethers.providers.Web3Provider) {
let accounts = await this.signer.listAccounts();
if (!accounts?.length) {
accounts = await this.signer.send('eth_requestAccounts', []);
if (!accounts?.length) {
throw Error(`getSigner failed, accounts:accounts`);
}
}
if (account) {
if (!accounts.find(item => item.toString().toLowerCase() === account.toLowerCase())) {
throw Error(`Account mismatch, account:account.toLowerCase(), but connected accounts:accounts`);
}
signer = this.signer.getSigner(account);
}
else {
signer = this.signer.getSigner(accounts[0]);
}
if (this.signer.provider?.isMetaMask && this.signer.provider?.request) {
const chainId = await signer.getChainId();
if (chainId != this.chainId) {
await this.signer.provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x' + Number(this.chainId).toString(16) }]
});
}
else {
return signer;
}
}
}
else {
signer = this.signer;
const signerAddress = await signer.getAddress();
if (account) {
if (account.toLowerCase() !== signerAddress.toLowerCase()) {
throw Error(`Account mismatch, account: account.toLowerCase(), but signer: signerAddress.toLowerCase()`);
}
}
}
// const chainId = await signer.getChainId()
// if (chainId != this.chainId) {
// throw Error(`chainId mismatch, chainId: chainId, but expected chainId: this.chainId`)
// }
return signer;
}
async getCurrentAccount() {
let signer;
if (this.signer instanceof ethers_1.ethers.providers.Web3Provider) {
let accounts = await this.signer.listAccounts();
if (accounts?.length) {
return accounts[0].toLowerCase();
}
accounts = await this.signer.send('eth_requestAccounts', []);
if (accounts?.length) {
return accounts[0].toLowerCase();
}
throw Error('getCurrentAccount failed, please connect web3, and choose a account.');
}
else {
signer = this.signer;
const account = await signer.getAddress();
return account.toLowerCase();
}
}
async approveERC20Proxy(account, erc20Address, spender, gasParams, allowance) {
const amount = allowance || ethers_1.ethers.constants.MaxInt256.toString();
const transaction = await erc20Contract.populateTransaction.approve(spender, amount);
if (transaction.data) {
return this.ethSend({
from: account,
to: erc20Address,
data: transaction.data,
gasPrice: gasParams?.gasPrice,
maxFeePerGas: gasParams?.maxFeePerGas,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas
});
}
throw Error(`approveERC20Proxy failed, account=account, erc20Address =erc20Address, spender=spender.`);
}
async approveERC721Proxy(account, erc721Address, operator, gasParams, approved = true) {
const transaction = await erc721Contract.populateTransaction.setApprovalForAll(operator, approved);
if (transaction.data) {
return this.ethSend({
from: account,
to: erc721Address,
data: transaction.data,
gasPrice: gasParams?.gasPrice,
maxFeePerGas: gasParams?.maxFeePerGas,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas
});
}
throw Error(`approveERC721Proxy failed, account=account, erc721Address =erc721Address, operator=operator.`);
}
async approveERC1155Proxy(account, erc1155Address, operator, gasParams, approved = true) {
const transaction = await erc1155Contract.populateTransaction.setApprovalForAll(operator, approved);
if (transaction.data) {
return this.ethSend({
from: account,
to: erc1155Address,
data: transaction.data,
gasPrice: gasParams?.gasPrice,
maxFeePerGas: gasParams?.maxFeePerGas,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas
});
}
throw Error(`approveERC1155Proxy failed, account=account, erc1155Address =erc1155Address, operator=operator.`);
}
}
exports.Web3Signer = Web3Signer;
//# sourceMappingURL=Web3Signer.js.map
FILE:scripts/lib/code/src/types/types.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetSchema = exports.Market = exports.Standard = exports.SaleKind = exports.OrderSide = exports.Network = exports.ETH_TOKEN_ADDRESS = exports.NULL_ADDRESS = void 0;
exports.NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
exports.ETH_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
var Network;
(function (Network) {
Network["ETH"] = "eth";
Network["BSC"] = "bsc";
Network["Polygon"] = "polygon";
Network["Avalanche"] = "avalanche";
Network["Arbitrum"] = "arbitrum";
Network["ZkSync"] = "zksync";
Network["Linea"] = "linea";
Network["Base"] = "base";
Network["OpBNB"] = "opbnb";
Network["Scroll"] = "scroll";
Network["MantaPacific"] = "manta_pacific";
Network["Optimism"] = "optimism";
Network["Mantle"] = "mantle";
Network["ZKFair"] = "zkfair";
Network["Blast"] = "blast";
Network["Merlin"] = "merlin";
Network["Mode"] = "mode";
Network["Cyber"] = "cyber";
Network["BOB"] = "bob";
Network["Lightlink"] = "lightlink";
Network["Nanon"] = "nanon";
Network["Bera"] = "bera";
Network["Zeta"] = "zeta";
Network["Nibiru"] = "nibiru";
Network["Abstract"] = "abstract";
Network["Monad"] = "monad";
Network["Bitlayer"] = "bitlayer";
Network["Mantra"] = "mantra";
})(Network || (exports.Network = Network = {}));
var OrderSide;
(function (OrderSide) {
OrderSide[OrderSide["BuyOrder"] = 0] = "BuyOrder";
OrderSide[OrderSide["SellOrder"] = 1] = "SellOrder";
})(OrderSide || (exports.OrderSide = OrderSide = {}));
var SaleKind;
(function (SaleKind) {
SaleKind[SaleKind["FixedPrice"] = 0] = "FixedPrice";
SaleKind[SaleKind["BatchSignedERC721Order"] = 3] = "BatchSignedERC721Order";
SaleKind[SaleKind["ContractOffer"] = 7] = "ContractOffer";
SaleKind[SaleKind["BatchOfferERC721s"] = 8] = "BatchOfferERC721s";
})(SaleKind || (exports.SaleKind = SaleKind = {}));
var Standard;
(function (Standard) {
Standard["ElementEx"] = "element-ex-v3";
})(Standard || (exports.Standard = Standard = {}));
var Market;
(function (Market) {
Market["ElementEx"] = "element";
})(Market || (exports.Market = Market = {}));
var AssetSchema;
(function (AssetSchema) {
AssetSchema["ERC721"] = "ERC721";
AssetSchema["ERC1155"] = "ERC1155";
})(AssetSchema || (exports.AssetSchema = AssetSchema = {}));
//# sourceMappingURL=types.js.map
FILE:scripts/lib/code/src/util/tokenUtil.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toContractERC20Token = toContractERC20Token;
exports.toStandardERC20Token = toStandardERC20Token;
const types_1 = require("../types/types");
function toContractERC20Token(erc20Token) {
if (erc20Token && erc20Token.toLowerCase() != types_1.NULL_ADDRESS) {
return erc20Token.toLowerCase();
}
return types_1.ETH_TOKEN_ADDRESS;
}
function toStandardERC20Token(erc20Token) {
if (erc20Token && erc20Token.toLowerCase() != types_1.ETH_TOKEN_ADDRESS) {
return erc20Token.toLowerCase();
}
return types_1.NULL_ADDRESS;
}
//# sourceMappingURL=tokenUtil.js.map
FILE:scripts/lib/code/src/util/receiptUtil.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBoughtAssets = getBoughtAssets;
const types_1 = require("../types/types");
const ethers_1 = require("ethers");
const BYTE32_0 = '0x0000000000000000000000000000000000000000000000000000000000000000';
const topicTransfer = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
const topicTransferSingle = '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62';
function getBoughtAssets(receipt) {
if (!receipt.from || !receipt.logs) {
return [];
}
const list = [];
const from = receipt.from.toLowerCase();
for (const log of receipt.logs) {
if (log.topics?.length == 4 &&
log.topics[0].toLowerCase() == topicTransfer &&
log.topics[1].toLowerCase() != BYTE32_0 &&
ethers_1.BigNumber.from(log.topics[2].toLowerCase()).eq(from)) {
list.push({
assetId: ethers_1.BigNumber.from(log.topics[3]).toString(),
assetAddress: log.address.toLowerCase(),
assetSchema: types_1.AssetSchema.ERC721,
quantity: '1'
});
continue;
}
if (log.topics?.length == 4 &&
log.data?.length == 130 &&
log.topics[0].toLowerCase() == topicTransferSingle &&
log.topics[2].toLowerCase() != BYTE32_0 &&
ethers_1.BigNumber.from(log.topics[3].toLowerCase()).eq(from)) {
list.push({
assetId: ethers_1.BigNumber.from(log.data.substring(0, 66)).toString(),
assetAddress: log.address.toLowerCase(),
assetSchema: types_1.AssetSchema.ERC1155,
quantity: ethers_1.BigNumber.from('0x' + log.data.substring(66)).toString()
});
}
}
return list;
}
//# sourceMappingURL=receiptUtil.js.map
FILE:scripts/lib/code/src/util/chainUtil.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getChain = getChain;
exports.getChainMId = getChainMId;
exports.getChainId = getChainId;
const types_1 = require("../types/types");
const CHAIN_NAMES = {
1: types_1.Network.ETH,
11155111: types_1.Network.ETH,
56: types_1.Network.BSC,
97: types_1.Network.BSC,
137: types_1.Network.Polygon,
43114: types_1.Network.Avalanche,
42161: types_1.Network.Arbitrum,
324: types_1.Network.ZkSync,
59144: types_1.Network.Linea,
8453: types_1.Network.Base,
204: types_1.Network.OpBNB,
534352: types_1.Network.Scroll,
169: types_1.Network.MantaPacific,
10: types_1.Network.Optimism,
5000: types_1.Network.Mantle,
42766: types_1.Network.ZKFair,
81457: types_1.Network.Blast,
4200: types_1.Network.Merlin,
34443: types_1.Network.Mode,
7560: types_1.Network.Cyber,
60808: types_1.Network.BOB,
1890: types_1.Network.Lightlink,
2748: types_1.Network.Nanon,
80094: types_1.Network.Bera,
7000: types_1.Network.Zeta,
6900: types_1.Network.Nibiru,
2741: types_1.Network.Abstract,
143: types_1.Network.Monad,
200901: types_1.Network.Bitlayer,
5888: types_1.Network.Mantra,
};
// Element 平台全局唯一 ChainMId 映射 (chainId -> chainMId)
const CHAIN_MID_MAP = {
1: 1, // Ethereum Mainnet
137: 101, // Polygon Mainnet
56: 201, // BSC Mainnet
43114: 401, // Avalanche Mainnet
42161: 601, // Arbitrum Mainnet
324: 701, // zkSync Era Mainnet
204: 1101, // opBNB Mainnet
8453: 1201, // Base Mainnet
534352: 1301, // Scroll Mainnet
169: 1401, // Manta Pacific
10: 1501, // Optimism Mainnet
5000: 1601, // Mantle Mainnet
42766: 1701, // ZKFair Mainnet
81457: 1801, // Blast Mainnet
4200: 1901, // Merlin Mainnet
34443: 2001, // Mode Mainnet
7560: 2101, // Cyber Mainnet
60808: 2201, // BOB Mainnet
1890: 2301, // Lightlink Mainnet
2748: 2501, // Nanon Mainnet
80094: 2601, // BeraChain Mainnet
7000: 2701, // ZetaChain Mainnet
6900: 2801, // Nibiru Mainnet
2741: 2901, // Abstract Mainnet
143: 3001, // Monad Mainnet
200901: 3101, // Bitlayer Mainnet
5888: 3201, // Mantra Mainnet
};
function getChain(chainId) {
if (CHAIN_NAMES[chainId]) {
return CHAIN_NAMES[chainId];
}
throw Error('getChain, unsupported chainId : ' + chainId);
}
/**
* 根据 chainId 获取 Element 平台的 chainMId
* @param chainId 区块链原生 chainId
* @returns Element 平台全局唯一 chainMId
*/
function getChainMId(chainId) {
if (CHAIN_MID_MAP[chainId]) {
return CHAIN_MID_MAP[chainId];
}
throw Error('getChainMId, unsupported chainId : ' + chainId);
}
function getChainId(chain, isTestnet = false) {
if (isTestnet) {
switch (chain.toString()) {
case types_1.Network.ETH:
return 11155111;
case types_1.Network.BSC:
return 97;
}
throw Error('getChainId, unsupported chain : ' + chain);
}
else {
switch (chain.toString()) {
case types_1.Network.ETH:
return 1;
case types_1.Network.BSC:
return 56;
case types_1.Network.Polygon:
return 137;
case types_1.Network.Avalanche:
return 43114;
case types_1.Network.Arbitrum:
return 42161;
case types_1.Network.ZkSync:
return 324;
case types_1.Network.Linea:
return 59144;
case types_1.Network.Base:
return 8453;
case types_1.Network.OpBNB:
return 204;
case types_1.Network.Scroll:
return 534352;
case types_1.Network.MantaPacific:
return 169;
case types_1.Network.Optimism:
return 10;
case types_1.Network.Mantle:
return 5000;
case types_1.Network.ZKFair:
return 42766;
case types_1.Network.Blast:
return 81457;
case types_1.Network.Merlin:
return 4200;
case types_1.Network.Mode:
return 34443;
case types_1.Network.Cyber:
return 7560;
case types_1.Network.BOB:
return 60808;
case types_1.Network.Lightlink:
return 1890;
case types_1.Network.Nanon:
return 2748;
case types_1.Network.Bera:
return 80094;
case types_1.Network.Zeta:
return 7000;
case types_1.Network.Nibiru:
return 6900;
case types_1.Network.Abstract:
return 2741;
case types_1.Network.Monad:
return 143;
case types_1.Network.Bitlayer:
return 200901;
case types_1.Network.Mantra:
return 5888;
}
throw Error('getChainId, unsupported chain : ' + chain);
}
}
//# sourceMappingURL=chainUtil.js.map
FILE:scripts/lib/code/src/util/assetUtil.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.erc20Decimals = erc20Decimals;
exports.approveERC20 = approveERC20;
exports.setApproveForAll = setApproveForAll;
exports.transferERC721 = transferERC721;
exports.transferERC1155 = transferERC1155;
const ethers_1 = require("ethers");
const config_1 = require("../contracts/config");
async function erc20Decimals(web3Signer, tokenAddress) {
const signer = await web3Signer.getSigner();
const contract = new ethers_1.Contract(tokenAddress, config_1.ContractABI.erc20.abi, signer);
return await contract.decimals();
}
async function approveERC20(web3Signer, tokenAddress, value, gasParams) {
if (value.eq(0)) {
return;
}
const chainId = web3Signer.chainId;
const signer = await web3Signer.getSigner();
const owner = await signer.getAddress();
const elementEx = config_1.CONTRACTS_ADDRESSES[chainId].ElementEx;
const contract = new ethers_1.Contract(tokenAddress, config_1.ContractABI.erc20.abi, signer);
const allowance = await contract.allowance(owner, elementEx);
if (allowance.lt(value)) {
const tx = await web3Signer.approveERC20Proxy(owner, tokenAddress, elementEx, gasParams);
await tx.wait();
}
}
async function setApproveForAll(web3Signer, tokenAddress, gasParams) {
const chainId = web3Signer.chainId;
const signer = await web3Signer.getSigner();
const owner = await signer.getAddress();
const elementEx = config_1.CONTRACTS_ADDRESSES[chainId].ElementEx;
const contract = new ethers_1.Contract(tokenAddress, config_1.ContractABI.erc721.abi, signer);
const approved = await contract.isApprovedForAll(owner, elementEx);
if (!approved) {
const tx = await web3Signer.approveERC721Proxy(owner, tokenAddress, elementEx, gasParams);
await tx.wait();
}
}
async function transferERC721(web3Signer, tokenAddress, tokenId, toAddress, gasParams) {
const signer = await web3Signer.getSigner();
const contract = new ethers_1.Contract(tokenAddress, config_1.ContractABI.erc721.abi, signer);
const fromAddress = await signer.getAddress();
// Check if contract supports safeTransferFrom
const safeTransferFragment = contract.interface.getFunction('safeTransferFrom');
if (!safeTransferFragment) {
throw new Error('Contract does not support safeTransferFrom');
}
// Use safeTransferFrom(address from, address to, uint256 tokenId)
const tx = await contract.safeTransferFrom(fromAddress, toAddress, tokenId, gasParams || {});
return await tx.wait();
}
async function transferERC1155(web3Signer, tokenAddress, tokenId, toAddress, quantity, gasParams) {
const signer = await web3Signer.getSigner();
const fromAddress = await signer.getAddress();
// Check if contract supports safeTransferFrom
const contract = new ethers_1.Contract(tokenAddress, config_1.ContractABI.erc1155.abi, signer);
const safeTransferFragment = contract.interface.getFunction('safeTransferFrom');
if (!safeTransferFragment) {
throw new Error('Contract does not support safeTransferFrom');
}
// Use safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data)
const tx = await contract.safeTransferFrom(fromAddress, toAddress, tokenId, quantity, '0x', gasParams || {});
return await tx.wait();
}
//# sourceMappingURL=assetUtil.js.map
FILE:scripts/lib/code/src/util/bitsUtil.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeBits = encodeBits;
const ethers_1 = require("ethers");
function encodeBits(args) {
let data = '0x';
for (const arg of args) {
data += toHexBytes(ethers_1.BigNumber.from(arg[0].toString()).toHexString(), arg[1]);
}
return data;
}
function toHexBytes(hexStr, bitCount) {
const count = bitCount / 4;
const str = hexStr.toLowerCase().startsWith('0x') ? hexStr.substring(2).toLowerCase() : hexStr.toLowerCase();
if (str.length > count) {
return str.substring(str.length - count);
}
let zero = '';
for (let i = str.length; i < count; i++) {
zero += '0';
}
return zero + str;
}
//# sourceMappingURL=bitsUtil.js.map
FILE:scripts/lib/code/src/util/gasUtil.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.estimateGas = estimateGas;
const axios_1 = __importDefault(require("axios"));
async function estimateGas(chainId) {
if (chainId == 137) {
return estimateGasPolygon();
}
}
async function estimateGasPolygon() {
try {
const response = await (0, axios_1.default)({
method: "get",
url: "https://gasstation.polygon.technology/v2",
timeout: 5000,
});
const obj = await response.data;
const fastMaxPriorityFee = Number.parseFloat(obj.fast.maxPriorityFee);
const baseFee = Number.parseFloat(obj.estimatedBaseFee);
let maxPriorityFee = Math.floor(fastMaxPriorityFee * 1e9);
let estimatedBaseFee;
if (baseFee >= 10) {
estimatedBaseFee = Math.floor(baseFee * 1.125 * 1e9);
}
else if (baseFee >= 5) {
estimatedBaseFee = Math.floor(baseFee * 1.5 * 1e9);
}
else {
estimatedBaseFee = Math.floor(baseFee * 2 * 1e9);
}
return {
maxFeePerGas: maxPriorityFee + estimatedBaseFee,
maxPriorityFeePerGas: maxPriorityFee,
};
}
catch (e) { }
}
//# sourceMappingURL=gasUtil.js.map
FILE:scripts/lib/code/src/util/numberUtil.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toString = toString;
exports.toNumber = toNumber;
exports.toHexValue = toHexValue;
const ethers_1 = require("ethers");
function toString(val) {
if (val != null) {
if (typeof (val) == 'number') {
return ethers_1.BigNumber.from('0x' + val.toString(16)).toString();
}
return ethers_1.BigNumber.from(val).toString();
}
return '';
}
function toNumber(val) {
return val != null ? Number(val.toString()) : undefined;
}
function toHexValue(value) {
const hex = ethers_1.BigNumber.from(value).toHexString();
if (hex.startsWith('0x0') && hex.length > 3) {
return '0x' + hex.substring(3);
}
return hex;
}
//# sourceMappingURL=numberUtil.js.map
FILE:scripts/lib/code/src/contracts/config.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RPC_CONF_API_URL = exports.CONTRACTS_ADDRESSES = exports.ContractABI = void 0;
exports.fetchRpcConfigs = fetchRpcConfigs;
exports.getCachedRpcConfigs = getCachedRpcConfigs;
exports.getRpcUrlFromRemote = getRpcUrlFromRemote;
var index_1 = require("./abi/index");
Object.defineProperty(exports, "ContractABI", { enumerable: true, get: function () { return index_1.ContractABI; } });
exports.CONTRACTS_ADDRESSES = {
1: {
ElementEx: '0x20F780A973856B93f63670377900C1d2a50a77c4',
ElementExSwapV2: '0xb4E7B8946fA2b35912Cc0581772cCCd69A33000c',
Helper: '0x68dc8D3ab93220e84b9923706B3DDc926C77f1Df',
WToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
},
11155111: {
ElementEx: '0x5df0d6a56523d49650a2526873c2c055201aa879',
ElementExSwapV2: '0xfb099ce799d8ea457cd7a4401d621c00d87c87fa',
Helper: '0x7a758546926f19b2dcffd114a36b3c8e04be7475',
WToken: '0x097d90c9d3e0b50ca60e1ae45f6a81010f9fb534'
},
56: {
ElementEx: '0xb3e3DfCb2d9f3DdE16d78B9e6EB3538Eb32B5ae1',
ElementExSwapV2: '0x46A03313FA8eF8ac8798f502bB38d35E5e1acbfC',
Helper: '0xb54ee46dACE4ecAC1dBC2488B61094B4b3174139',
WToken: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
},
97: {
ElementEx: '0x30FAD3918084eba4379FD01e441A3Bb9902f0843',
ElementExSwapV2: '0x8751796ba398412A1520fa177E421183C49a8780',
Helper: '0x61311202273f9857685852FC76aEA83294F90a80',
WToken: '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd'
},
137: {
ElementEx: '0xEAF5453b329Eb38Be159a872a6ce91c9A8fb0260',
ElementExSwapV2: '0x25956Fd0A5FE281D921b1bB3499fc8D5EFea6201',
Helper: '0x4D5E03AF11d7976a0494f0ff2F65986d6548fc3e',
WToken: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270'
},
80001: {
ElementEx: '0x2431e7671d1557d991a138c7af5d4cd223a605d6',
ElementExSwapV2: '0xA9fF4783fA66bc2774f2c41489BA570EbE82E141',
Helper: '0xcCcd0afEAfB6625cd655Cf8f39B02c85947dB6f6',
WToken: '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889'
},
43114: {
ElementEx: '0x18cd9270DbdcA86d470cfB3be1B156241fFfA9De',
ElementExSwapV2: '0x917ef4F231Cbd0972A10eC3453F40762C488e6fa',
Helper: '0x4c95419b74D420841CaaAd6345799522475f91D2',
WToken: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7'
},
43113: {
ElementEx: '0xd089757a20a36B0978156659Cc1063B929Da76aB',
ElementExSwapV2: '0x786596CFaA0020EC7fFdE499049E3b9981E99f4A',
Helper: '0x1f66918D87aab33158DBA4b5Dfe73f2245cfDc20',
WToken: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c'
},
42161: {
ElementEx: '0x18cd9270dbdca86d470cfb3be1b156241fffa9de',
ElementExSwapV2: '0x1e0E556b7f310c320bA22b5dEC0A0755C1c9854b',
Helper: '0xb4E7B8946fA2b35912Cc0581772cCCd69A33000c',
WToken: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1'
},
421613: {
ElementEx: '0x6938d12679ba4e646934a6900bd4077c3cc09a04',
ElementExSwapV2: '0xf6bD4a8dfe1FB577C311Bd361CB1b0e7DD3b83ab',
Helper: '0xccf79726adA5333B41793994fAe78a28F0c6278A',
WToken: '0x204a6679557ec1adfb3752c88891aa885adb53f1'
},
324: {
ElementEx: '0x64848eefbc2921102a153b08fa64536ae1f8e937',
ElementExSwapV2: '0x7868a55b638ed298370c16f83fa32b26664726ab',
Helper: '0x4ff83aa3a2a993270c7921ce6f22892213c3c446',
WToken: '0x5aea5775959fbc2557cc8789bc1bf90a239d9a91'
},
280: {
ElementEx: '0x0ec4d499f46a154e7faf52c1695b2da8a41900d4',
ElementExSwapV2: '0x448798ccc3a9d15ce5d4369c928c86b4085c106d',
Helper: '0xbc91448f965c684238686532f17492d207f0a9b7',
WToken: '0xf8dcf9b36817151d36ff2e35d9f43094dde4c737'
},
59144: {
ElementEx: '0x0caB6977a9c70E04458b740476B498B214019641',
ElementExSwapV2: '0x42c759a719c228050901299b88fd316c3a050617',
Helper: '0x701a4A5238AF84a9c4ed8a23DeE670069b44eEb7',
WToken: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
},
59140: {
ElementEx: '0xc23cf8BC7cD2f2Dcb2e151E81b8a1F9EA7c017B6',
ElementExSwapV2: '0x4B2C3677432a918F197B9c546d0844f53d374eB0',
Helper: '0x9A6324eBF46288FD872c08BA7C6e51fbb62dC259',
WToken: '0x2C1b868d6596a18e32E61B901E4060C872647b6C'
},
8453: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0x66950320086664429C69735318724Ae24ec0D835',
Helper: '0x217efe077801387d125fE98E1b61CDDA4D1364d2',
WToken: '0x4200000000000000000000000000000000000006'
},
84531: {
ElementEx: '0x8237A37FC696D944d4Cdb089A89443B55Cb5e7F9',
ElementExSwapV2: '0xcCcd0afEAfB6625cd655Cf8f39B02c85947dB6f6',
Helper: '0x89A34a7EDC273555bB11ba4484ec417B05df3a15',
WToken: '0x4200000000000000000000000000000000000006'
},
204: {
ElementEx: '0x5417c5215F239B8D04f9D9c04bF43034B35AD4BD',
ElementExSwapV2: '0x8629E04a83902721FBD816fE9d41FD2053DAC79b',
Helper: '0x3c19784F5247ca471E27eA1C604b48D266eb000C',
WToken: '0x4200000000000000000000000000000000000006'
},
10: {
ElementEx: '0x2317d8b224328644759319dffa2a5da77c72e0e9',
ElementExSwapV2: '0xc9605a76b0370e148b4a510757685949f13248c7',
Helper: '0xbe6461385106793d2099399358d233c934d41581',
WToken: '0x4200000000000000000000000000000000000006'
},
534352: {
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0x217efe077801387d125fe98e1b61cdda4d1364d2',
Helper: '0x17bab823e1b4716f9bbe9eefc274f55ddf4056fd',
WToken: '0x5300000000000000000000000000000000000004'
},
169: {
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0xbcfa22a36e555c507092ff16c1af4cb74b8514c8',
Helper: '0x4bd6ff0413a095a79a855d83399a4850476be81e',
WToken: '0x0dc808adce2099a9f62aa87d9670745aba741746'
},
5000: {
ElementEx: '0x2fa13cf695ec51ded5b8e45ad0bef838ab17e2af',
ElementExSwapV2: '0x9f47921d360aee0651a4f1ed2c4892b4923f9e52',
Helper: '0x4c95419b74d420841caaad6345799522475f91d2',
WToken: '0x78c1b0c915c4faa5fffa6cabf0219da63d7f4cb8'
},
42766: {
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0xc9605a76b0370e148b4a510757685949f13248c7',
Helper: '0x0fd3d35c4536134e48a6bc05558b8d870878e119',
WToken: '0xd33db7ec50a98164cc865dfaa64666906d79319c'
},
81457: {
ElementEx: '0x4196b39157659bf0de9ebf6e505648b7889a39ce',
ElementExSwapV2: '0xe29799ca0b98ba41343a4ea52fe15ed7d5e05662',
Helper: '0x0fd3d35c4536134e48a6bc05558b8d870878e119',
WToken: '0x4300000000000000000000000000000000000004'
},
4200: {
ElementEx: '0x4196b39157659bf0de9ebf6e505648b7889a39ce',
ElementExSwapV2: '0xe4ac19434cef450ead2942fa9ab01ec8fc0cf181',
Helper: '0x917ef4f231cbd0972a10ec3453f40762c488e6fa',
WToken: '0xf6d226f9dc15d9bb51182815b320d3fbe324e1ba'
},
//mode
34443: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0x2473e8d725f7b3eCa344c272F110948D63280f96',
Helper: '0x66950320086664429C69735318724Ae24ec0D835',
WToken: '0x4200000000000000000000000000000000000006'
},
//cyber
7560: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0xF937CDf1c6457c9b22ecC8310CE7c6374cF78353',
Helper: '0x4c95419b74D420841CaaAd6345799522475f91D2',
WToken: '0x4200000000000000000000000000000000000006'
},
//bob
60808: {
ElementEx: '0x2fa13cf695EC51Ded5B8E45Ad0BEf838aB17E2aF',
ElementExSwapV2: '0x2040491367062EA1Ae1c73Bc3961c6D0151Aa39f',
Helper: '0xfE357D8d1B285C846185b4Cae4F96bD81DF19445',
WToken: '0x4200000000000000000000000000000000000006'
},
// lightlink
1890: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0x66950320086664429C69735318724Ae24ec0D835',
Helper: '0x26Df6Fea89f1C9e4A3A2bfc2128542B7a05FbA8E',
WToken: '0x7EbeF2A4b1B09381Ec5B9dF8C5c6f2dBECA59c73'
},
//zeta
7000: {
ElementEx: '0x4196b39157659BF0De9ebF6E505648B7889a39cE',
ElementExSwapV2: '0x9f47921D360aeE0651A4F1ED2c4892B4923F9E52',
Helper: '0x66950320086664429C69735318724Ae24ec0D835',
WToken: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
},
//nibiru
6900: {
ElementEx: '0xa39A5f160a1952dDf38781Bd76E402B0006912A9',
ElementExSwapV2: '0xf71a05E3749b0F9611307A37AFE3d853Bd734E13',
Helper: '0xbe6461385106793d2099399358D233C934d41581',
WToken: '0x0CaCF669f8446BeCA826913a3c6B96aCD4b02a97'
},
//abstract
2741: {
ElementEx: '0x3f33a3dab9e6f691a11D0EEBDf93dA445A021096',
ElementExSwapV2: '0xA4306F9CeFC471447580C617905F49d43Df1Ece9',
Helper: '0xb82F08665d2DDD19F219FadD6e01701E876D41eC',
WToken: '0x3439153EB7AF838Ad19d56E1571FBD09333C2809'
},
//monad
143: {
ElementEx: '0x0cab6977a9c70e04458b740476b498b214019641',
ElementExSwapV2: '0x42c759a719c228050901299b88fd316c3a050617',
Helper: '0x701a4a5238af84a9c4ed8a23dee670069b44eeb7',
WToken: '0x3bd359c1119da7da1d913d1c4d2b7c461115433a'
},
//bitlayer
200901: {
ElementEx: '0x0caB6977a9c70E04458b740476B498B214019641',
ElementExSwapV2: '0xa52C8a12C728e95f1BeF74835b1316b7407b61A8',
Helper: '0xe29799cA0B98BA41343A4eA52Fe15ed7D5e05662',
WToken: '0xfF204e2681A6fA0e2C3FaDe68a1B28fb90E4Fc5F'
},
};
const RPC_URLS = {
1: 'https://api.zan.top/node/v1/eth/mainnet/6e96cfbcaff949bfbdaeb5fbc554ac7c',
};
// RPC 配置 API 地址
exports.RPC_CONF_API_URL = 'https://api.element.market/v1/quote/rpcConfInfo';
// 缓存的 RPC 配置
let cachedRpcConfigs = null;
let lastFetchTime = 0;
const CACHE_DURATION = 5 * 60 * 1000; // 5 分钟缓存
/**
* 从 HTTP 接口获取所有 RPC 配置
* @returns Promise<RpcConfInfo[]> RPC 配置列表
*/
async function fetchRpcConfigs() {
try {
const response = await fetch(exports.RPC_CONF_API_URL);
if (!response.ok) {
throw new Error(`HTTP error! status: response.status`);
}
const result = await response.json();
if (result.code !== 0) {
throw new Error(`API error: result.status`);
}
return result.data;
}
catch (error) {
console.error('Failed to fetch RPC configs:', error);
throw error;
}
}
/**
* 获取缓存的 RPC 配置(带缓存机制)
* @returns Promise<Map<number, RpcConfInfo>> 链 ID 到 RPC 配置的映射
*/
async function getCachedRpcConfigs() {
const now = Date.now();
if (cachedRpcConfigs && now - lastFetchTime < CACHE_DURATION) {
return cachedRpcConfigs;
}
const configs = await fetchRpcConfigs();
const filteredConfigs = configs.filter(config => !config.isWalletPriority);
cachedRpcConfigs = new Map(filteredConfigs.map(config => [config.chainMId, config]));
// 将 RPC_URLS 中的静态配置也加入缓存
Object.entries(RPC_URLS).forEach(([chainMId, rpcUrl]) => {
if (!cachedRpcConfigs.has(parseInt(chainMId))) {
cachedRpcConfigs.set(parseInt(chainMId), {
chainMId: parseInt(chainMId),
rpcUrl,
isWalletPriority: false
});
}
});
lastFetchTime = now;
return cachedRpcConfigs;
}
/**
* 从远程获取指定链的 RPC URL
* @param chainId 链 ID
* @returns Promise<string | undefined> RPC URL
*/
async function getRpcUrlFromRemote(chainMId) {
try {
const configs = await getCachedRpcConfigs();
const config = configs.get(chainMId);
return config?.rpcUrl;
}
catch (error) {
console.error(`Failed to get RPC URL for chain chainMId from remote:`, error);
return undefined;
}
}
//# sourceMappingURL=config.js.map
FILE:scripts/lib/code/src/contracts/abi/index.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContractABI = void 0;
const ERC20_json_1 = __importDefault(require("./common/ERC20.json"));
const ERC721_json_1 = __importDefault(require("./common/ERC721.json"));
const ERC1155_json_1 = __importDefault(require("./common/ERC1155.json"));
const WETH_json_1 = __importDefault(require("./common/WETH.json"));
const IElementEx_json_1 = __importDefault(require("./elementEx/IElementEx.json"));
const IElementExSwapV2_json_1 = __importDefault(require("./elementEx/IElementExSwapV2.json"));
const IAggTraderHelper_json_1 = __importDefault(require("./elementEx/IAggTraderHelper.json"));
exports.ContractABI = {
weth: WETH_json_1.default,
erc20: ERC20_json_1.default,
erc721: ERC721_json_1.default,
erc1155: ERC1155_json_1.default,
elementEx: IElementEx_json_1.default,
elementExSwap: IElementExSwapV2_json_1.default,
helper: IAggTraderHelper_json_1.default,
};
//# sourceMappingURL=index.js.map
FILE:scripts/lib/code/src/contracts/abi/common/ERC721.json
{
"contractName": "ERC721",
"abi": [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "approved",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "baseURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "getApproved",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "mint",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "uri",
"type": "string"
}
],
"name": "setBaseURI",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
}
FILE:scripts/lib/code/src/contracts/abi/common/ERC1155.json
{
"contractName": "ERC1155",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "values",
"type": "uint256[]"
}
],
"name": "TransferBatch",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "TransferSingle",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "value",
"type": "string"
},
{
"indexed": true,
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "URI",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "accounts",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
}
],
"name": "balanceOfBatch",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"name": "batchMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mintTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeBatchTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "uri",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "exists",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "creator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "_getOverrideURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
FILE:scripts/lib/code/src/contracts/abi/common/ERC20.json
{
"contractName": "ERC20",
"abi": [
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "who",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "owner",
"type": "address"
},
{
"indexed": true,
"name": "spender",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "spender",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
}
FILE:scripts/lib/code/src/contracts/abi/common/WETH.json
{
"contractName": "WETH9",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Withdrawal",
"type": "event"
},
{
"payable": true,
"stateMutability": "payable",
"type": "fallback"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "guy",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "dst",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "src",
"type": "address"
},
{
"internalType": "address",
"name": "dst",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "withdraw",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
}
FILE:scripts/lib/code/src/contracts/abi/elementEx/IElementExSwapV2.json
{
"_format": "hh-sol-artifact-1",
"contractName": "IElementExSwapV2",
"sourceName": "contracts/swap/IElementExSwapV2.sol",
"abi": [
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct IAggregator.ERC20Pair[]",
"name": "erc20Pairs",
"type": "tuple[]"
},
{
"internalType": "bytes",
"name": "tradeBytes",
"type": "bytes"
},
{
"internalType": "address[]",
"name": "dustTokens",
"type": "address[]"
}
],
"name": "batchBuyWithERC20s",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct IAggregator.ERC20Pair[]",
"name": "erc20Pairs",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "uint256",
"name": "marketId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "tradeData",
"type": "bytes"
}
],
"internalType": "struct ISimulator.TradeDetails[]",
"name": "tradeDetails",
"type": "tuple[]"
},
{
"internalType": "address[]",
"name": "dustTokens",
"type": "address[]"
}
],
"name": "batchBuyWithERC20sSimulate",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "tradeBytes",
"type": "bytes"
}
],
"name": "batchBuyWithETH",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "marketId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "tradeData",
"type": "bytes"
}
],
"internalType": "struct ISimulator.TradeDetails[]",
"name": "tradeDetails",
"type": "tuple[]"
}
],
"name": "batchBuyWithETHSimulate",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
FILE:scripts/lib/code/src/contracts/abi/elementEx/IAggTraderHelper.json
{
"_format": "hh-sol-artifact-1",
"contractName": "IAggTraderHelper",
"sourceName": "contracts/helper/IAggTraderHelper.sol",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "checkAssets",
"outputs": [
{
"components": [
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
}
],
"internalType": "struct IAssetCheckerFeature.AssetCheckResultInfo[]",
"name": "infos",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "uint8[]",
"name": "itemTypes",
"type": "uint8[]"
},
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "checkAssetsEx",
"outputs": [
{
"components": [
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
}
],
"internalType": "struct IAssetCheckerFeature.AssetCheckResultInfo[]",
"name": "infos",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "uint256",
"name": "listingTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "expirationTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "startNonce",
"type": "uint256"
},
{
"internalType": "address",
"name": "paymentToken",
"type": "address"
},
{
"internalType": "address",
"name": "platformFeeRecipient",
"type": "address"
},
{
"components": [
{
"internalType": "address",
"name": "nftAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "platformFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "royaltyFee",
"type": "uint256"
},
{
"internalType": "address",
"name": "royaltyFeeRecipient",
"type": "address"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItem[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollection[]",
"name": "basicCollections",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "address",
"name": "nftAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "platformFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "royaltyFee",
"type": "uint256"
},
{
"internalType": "address",
"name": "royaltyFeeRecipient",
"type": "address"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItem[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollection[]",
"name": "collections",
"type": "tuple[]"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSERC721Orders",
"name": "order",
"type": "tuple"
}
],
"name": "checkBSERC721Orders",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
},
{
"components": [
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"components": [
{
"internalType": "bool",
"name": "isNonceValid",
"type": "bool"
},
{
"internalType": "bool",
"name": "isERC20AmountValid",
"type": "bool"
},
{
"internalType": "address",
"name": "ownerOfNftId",
"type": "address"
},
{
"internalType": "address",
"name": "approvedAccountOfNftId",
"type": "address"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItemCheckResult[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollectionCheckResult[]",
"name": "basicCollections",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"components": [
{
"internalType": "bool",
"name": "isNonceValid",
"type": "bool"
},
{
"internalType": "bool",
"name": "isERC20AmountValid",
"type": "bool"
},
{
"internalType": "address",
"name": "ownerOfNftId",
"type": "address"
},
{
"internalType": "address",
"name": "approvedAccountOfNftId",
"type": "address"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSOrderItemCheckResult[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSCollectionCheckResult[]",
"name": "collections",
"type": "tuple[]"
}
],
"internalType": "struct IBatchSignedERC721OrdersCheckerFeature.BSERC721OrdersCheckResult",
"name": "r",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155SellAmount",
"type": "uint128"
}
],
"name": "checkERC1155BuyOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "ecr1155TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "sellAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155SellAmount",
"type": "uint128"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC1155BuyOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "ecr1155TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "sellAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155BuyOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
}
],
"name": "checkERC1155SellOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20WillPayAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "buyAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint128",
"name": "erc1155BuyAmount",
"type": "uint128"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC1155SellOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "erc1155RemainingAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "remainingAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc1155ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20WillPayAmount",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "buyAmountCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC1155SellOrderTakerCheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
}
],
"name": "checkERC721BuyOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "bool",
"name": "ecr721TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc721TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC721BuyOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "propertiesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "erc20Allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "erc20BalanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AllowanceCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721BuyOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "bool",
"name": "ecr721TokenIdCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
}
],
"name": "checkERC721SellOrder",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC20CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "checkERC721SellOrderEx",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "uint256",
"name": "hashNonce",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "makerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "expireTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "extraCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "nonceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "feesCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc20AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721AddressCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721OwnerCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "erc721ApprovedCheck",
"type": "bool"
},
{
"internalType": "uint256",
"name": "erc20TotalAmount",
"type": "uint256"
}
],
"internalType": "struct IElementExCheckerFeature.ERC721SellOrderCheckInfo",
"name": "info",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "balanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "allowanceCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "listingTimeCheck",
"type": "bool"
},
{
"internalType": "bool",
"name": "takerCheck",
"type": "bool"
}
],
"internalType": "struct IElementExCheckerFeature.ERC20CheckInfo",
"name": "takerCheckInfo",
"type": "tuple"
},
{
"internalType": "bool",
"name": "validSignature",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155BuyOrderInfo",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "status",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "orderAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "remainingAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.OrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC1155SellOrderInfo",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "enum LibNFTOrder.OrderStatus",
"name": "status",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "orderAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "remainingAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.OrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721BuyOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
}
],
"name": "getERC721SellOrderHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "maker",
"type": "address"
}
],
"name": "getHashNonce",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "accountNonce",
"type": "uint256"
}
],
"name": "getLooksRareCheckInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "transferManager",
"type": "address"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isExecutedOrCancelled",
"type": "bool"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.LooksRareCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "accountNonce",
"type": "uint256"
}
],
"name": "getLooksRareCheckInfoEx",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "transferManager",
"type": "address"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isExecutedOrCancelled",
"type": "bool"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.LooksRareCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"components": [
{
"internalType": "uint8",
"name": "tokenType",
"type": "uint8"
},
{
"internalType": "address",
"name": "tokenAddress",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"internalType": "struct ISDKApproveCheckerFeature.SDKApproveInfo[]",
"name": "list",
"type": "tuple[]"
}
],
"name": "getSDKApprovalsAndCounter",
"outputs": [
{
"internalType": "uint256[]",
"name": "approvals",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "elementCounter",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "seaportCounter",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "conduitKey",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"name": "getSeaportCheckInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "conduit",
"type": "address"
},
{
"internalType": "bool",
"name": "conduitExists",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isValidated",
"type": "bool"
},
{
"internalType": "bool",
"name": "isCancelled",
"type": "bool"
},
{
"internalType": "uint256",
"name": "totalFilled",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSize",
"type": "uint256"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.SeaportCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint8",
"name": "itemType",
"type": "uint8"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "conduitKey",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"name": "getSeaportCheckInfoEx",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "conduit",
"type": "address"
},
{
"internalType": "bool",
"name": "conduitExists",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155Balance",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isValidated",
"type": "bool"
},
{
"internalType": "bool",
"name": "isCancelled",
"type": "bool"
},
{
"internalType": "uint256",
"name": "totalFilled",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSize",
"type": "uint256"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.SeaportCheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
},
{
"internalType": "address",
"name": "executionDelegate",
"type": "address"
}
],
"name": "getX2y2CheckInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "erc721Owner",
"type": "address"
},
{
"internalType": "bool",
"name": "isApprovedForAll",
"type": "bool"
},
{
"internalType": "address",
"name": "erc721ApprovedAccount",
"type": "address"
},
{
"internalType": "enum IX2y2.InvStatus",
"name": "status",
"type": "uint8"
}
],
"internalType": "struct IThirdExchangeCheckerFeature.X2y2CheckInfo",
"name": "info",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "isERC1155OrderNonceCancelled",
"outputs": [
{
"internalType": "bool",
"name": "filled",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "isERC721OrderNonceFilled",
"outputs": [
{
"internalType": "bool",
"name": "filled",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "ens",
"type": "address"
},
{
"internalType": "bytes32[]",
"name": "nodes",
"type": "bytes32[]"
}
],
"name": "queryENSInfosByNode",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "address",
"name": "domainAddr",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "bool",
"name": "available",
"type": "bool"
}
],
"internalType": "struct IENSHelperFeature.ENSQueryResult[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "ens",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "queryENSInfosByToken",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "address",
"name": "domainAddr",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "bool",
"name": "available",
"type": "bool"
}
],
"internalType": "struct IENSHelperFeature.ENSQueryResult[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "ens",
"type": "address"
},
{
"internalType": "address[]",
"name": "addresses",
"type": "address[]"
}
],
"name": "queryENSReverseInfos",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "bytes",
"name": "domain",
"type": "bytes"
},
{
"internalType": "address",
"name": "verifyResolver",
"type": "address"
},
{
"internalType": "address",
"name": "verifyAddr",
"type": "address"
}
],
"internalType": "struct IENSHelperFeature.ENSReverseResult[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "resolver",
"type": "address"
},
{
"internalType": "string[]",
"name": "names",
"type": "string[]"
},
{
"internalType": "bytes32[]",
"name": "secrets",
"type": "bytes32[]"
},
{
"internalType": "uint256[]",
"name": "durations",
"type": "uint256[]"
}
],
"name": "querySpaceIdInfos",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "minCommitAge",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxCommitAge",
"type": "uint256"
},
{
"components": [
{
"internalType": "uint256",
"name": "base",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "premium",
"type": "uint256"
},
{
"internalType": "bool",
"name": "available",
"type": "bool"
},
{
"internalType": "bytes32",
"name": "commitHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "commitTimestamp",
"type": "uint256"
}
],
"internalType": "struct ISpaceIdHelperFeature.SpaceIdItem[]",
"name": "items",
"type": "tuple[]"
}
],
"internalType": "struct ISpaceIdHelperFeature.SpaceIdInfos",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "erc1155TokenProperties",
"type": "tuple[]"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155BuyOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC1155BuyOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "erc1155Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc1155TokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "erc1155TokenAmount",
"type": "uint128"
}
],
"internalType": "struct LibNFTOrder.ERC1155SellOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC1155SellOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
},
{
"components": [
{
"internalType": "contract IPropertyValidator",
"name": "propertyValidator",
"type": "address"
},
{
"internalType": "bytes",
"name": "propertyData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Property[]",
"name": "nftProperties",
"type": "tuple[]"
}
],
"internalType": "struct LibNFTOrder.NFTBuyOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC721BuyOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "taker",
"type": "address"
},
{
"internalType": "uint256",
"name": "expiry",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "contract IERC20",
"name": "erc20Token",
"type": "address"
},
{
"internalType": "uint256",
"name": "erc20TokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "feeData",
"type": "bytes"
}
],
"internalType": "struct LibNFTOrder.Fee[]",
"name": "fees",
"type": "tuple[]"
},
{
"internalType": "address",
"name": "nft",
"type": "address"
},
{
"internalType": "uint256",
"name": "nftId",
"type": "uint256"
}
],
"internalType": "struct LibNFTOrder.NFTSellOrder",
"name": "order",
"type": "tuple"
},
{
"components": [
{
"internalType": "enum LibSignature.SignatureType",
"name": "signatureType",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"internalType": "struct LibSignature.Signature",
"name": "signature",
"type": "tuple"
}
],
"name": "validateERC721SellOrderSignature",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
FILE:scripts/lib/code/src/contracts/contracts.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContractABI = void 0;
exports.getElementExContract = getElementExContract;
exports.getHelperContract = getHelperContract;
const config_1 = require("./config");
const ethers_1 = require("ethers");
var index_1 = require("./abi/index");
Object.defineProperty(exports, "ContractABI", { enumerable: true, get: function () { return index_1.ContractABI; } });
function getElementExContract(chainId, signer) {
const address = config_1.CONTRACTS_ADDRESSES[chainId].ElementEx;
return new ethers_1.Contract(address, config_1.ContractABI.elementEx.abi, signer);
}
// export function getElementExSwapContract(chainId: number, signer: Signer): Contract {
// const address = CONTRACTS_ADDRESSES[chainId as keyof typeof CONTRACTS_ADDRESSES].ElementExSwapV2
// return new Contract(address, ContractABI.elementExSwap.abi, signer)
// }
function getHelperContract(chainId, signer) {
const address = config_1.CONTRACTS_ADDRESSES[chainId].Helper;
return new ethers_1.Contract(address, config_1.ContractABI.helper.abi, signer);
}
//# sourceMappingURL=contracts.js.map
FILE:scripts/lib/code/src/element/order/orderConverter.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toOrderInformation = toOrderInformation;
exports.toOrderRequest = toOrderRequest;
const ethers_1 = require("ethers");
const chainUtil_1 = require("../../util/chainUtil");
const config_1 = require("../../contracts/config");
const types_1 = require("../../types/types");
const bitsUtil_1 = require("../../util/bitsUtil");
const tokenUtil_1 = require("../../util/tokenUtil");
function toOrderInformation(order, orderId) {
let price = order.basePrice;
if (order.quantity) {
price = ethers_1.BigNumber.from(order.basePrice).div(order.quantity).toString();
}
return {
contractAddress: order.metadata.asset.address,
tokenId: order.metadata.asset.id,
schema: order.metadata.schema,
standard: types_1.Standard.ElementEx,
maker: order.maker,
listingTime: Number(order.listingTime),
expirationTime: Number(order.expirationTime),
price: Number(ethers_1.ethers.utils.formatEther(price)),
paymentToken: order.paymentToken,
saleKind: order.saleKind,
side: order.side,
orderId
};
}
function toOrderRequest(signedOrder) {
const { order, signature, chainId } = signedOrder;
const chain = (0, chainUtil_1.getChain)(chainId);
const exchange = config_1.CONTRACTS_ADDRESSES[chainId].ElementEx;
const info = parseOrder(order);
const expiry = decodeExpiry(order.expiry);
const totalERC20Amount = calcTotalERC20Amount(order);
const paymentToken = (0, tokenUtil_1.toStandardERC20Token)(order.erc20Token);
const request = {
exchange: exchange.toLowerCase(),
maker: order.maker.toLowerCase(),
taker: order.taker.toLowerCase(),
side: info.side,
saleKind: expiry.saleKind,
oracleSignature: expiry.oracleSignature,
paymentToken: paymentToken,
quantity: info.quantity,
basePrice: totalERC20Amount,
extra: expiry.extra,
listingTime: expiry.listingTime,
expirationTime: expiry.expirationTime,
metadata: info.metadata,
fees: toLowerCaseFees(order.fees),
nonce: order.nonce,
hashNonce: order.hashNonce,
hash: signedOrder.orderHash,
signatureType: signature.signatureType,
v: signature.v,
r: signature.r,
s: signature.s,
chain: chain
};
if (info.properties != null) {
request.properties = toLowerCaseProperties(info.properties);
if (request.properties.length > 0) {
request.saleKind = types_1.SaleKind.ContractOffer;
}
}
return request;
}
function toLowerCaseFees(fees) {
return fees.map(fee => ({
recipient: fee.recipient.toLowerCase(),
amount: ethers_1.BigNumber.from(fee.amount).toString(),
feeData: fee.feeData
}));
}
function toLowerCaseProperties(properties) {
return properties.map(property => ({
propertyValidator: property.propertyValidator.toLowerCase(),
propertyData: property.propertyData
}));
}
function calcTotalERC20Amount(order) {
let total = ethers_1.BigNumber.from(order.erc20TokenAmount);
for (let i = 0; i < order.fees.length; i++) {
total = total.add(order.fees[i].amount);
}
return total.toString();
}
function parseOrder(order) {
let side;
let quantity;
let metadata;
let properties;
if (order['nft'] != undefined) {
quantity = '1';
metadata = {
asset: {
id: order['nftId'],
address: order['nft'].toString().toLowerCase()
},
schema: types_1.AssetSchema.ERC721
};
if (order['nftProperties'] != undefined) {
side = types_1.OrderSide.BuyOrder;
properties = toLowerCaseProperties(order['nftProperties']);
}
else {
side = types_1.OrderSide.SellOrder;
properties = undefined;
}
}
else if (order['erc1155Token'] != undefined) {
quantity = order['erc1155TokenAmount'];
metadata = {
asset: {
id: order['erc1155TokenId'],
address: order['erc1155Token'].toString().toLowerCase()
},
schema: types_1.AssetSchema.ERC1155
};
if (order['erc1155TokenProperties'] != undefined) {
side = types_1.OrderSide.BuyOrder;
properties = toLowerCaseProperties(order['erc1155TokenProperties']);
}
else {
side = types_1.OrderSide.SellOrder;
properties = undefined;
}
}
else {
throw Error('toOrderStr error');
}
return { side, quantity, metadata, properties };
}
function decodeExpiry(expiry) {
// saleKind (4bit) + reserved(156bit) + extra(32bit) + listingTime(32bit) + expiryTime(32bit) = 256bit
const hex = (0, bitsUtil_1.encodeBits)([[expiry, 256]]).substring(2);
const orderSaleKindHex = '0x' + hex.substring(0, 1);
const oracleSignatureHex = '0x' + hex.substring(1, 2);
const extraHex = '0x' + hex.substring(40, 48);
const listingTimeHex = '0x' + hex.substring(48, 56);
const expiryTimeHex = '0x' + hex.substring(56, 64);
return {
saleKind: parseInt(orderSaleKindHex),
oracleSignature: parseInt(oracleSignatureHex),
extra: parseInt(extraHex).toString(),
listingTime: parseInt(listingTimeHex),
expirationTime: parseInt(expiryTimeHex)
};
}
//# sourceMappingURL=orderConverter.js.map
FILE:scripts/lib/code/src/element/order/orderManager.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OrderManager = void 0;
const Web3Signer_1 = require("../../signer/Web3Signer");
const contracts_1 = require("../../contracts/contracts");
const config_1 = require("../../contracts/config");
const ethers_1 = require("ethers");
const orderTypes_1 = require("./orderTypes");
const types_1 = require("../../types/types");
const tokenUtil_1 = require("../../util/tokenUtil");
const orderTypedData_1 = require("./orderTypedData");
const bitsUtil_1 = require("../../util/bitsUtil");
class OrderManager {
constructor(web3Signer) {
this.web3Signer = web3Signer;
this.WETH = config_1.CONTRACTS_ADDRESSES[web3Signer.chainId].WToken;
}
async cancelERC721Orders(signedOrders, gasParams) {
const nonces = [];
for (const signedOrder of signedOrders) {
nonces.push(signedOrder.order ? signedOrder.order.nonce : signedOrder.nonce);
}
const elementEx = await this.getElementEx();
const tx = await elementEx.populateTransaction.batchCancelERC721Orders(nonces);
if (!tx?.data) {
throw Error("cancelOrder failed, populateTransaction error.");
}
const from = await this.web3Signer.getCurrentAccount();
const call = {
from: from,
to: elementEx.address,
data: tx.data,
gasPrice: gasParams.gasPrice,
maxPriorityFeePerGas: gasParams.maxPriorityFeePerGas,
maxFeePerGas: gasParams.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
async createSellOrder(params, gasParams) {
const expiry = getOrderExpiry(params);
const fees = calcFees(params);
const erc20TokenAmount = calcERC20TokenAmount(params, fees);
const order = {
maker: params.makerAddress.toLowerCase(),
taker: params.takerAddress.toLowerCase(),
expiry: expiry,
nonce: ethers_1.BigNumber.from(params.nonce).toString(),
erc20Token: (0, tokenUtil_1.toContractERC20Token)(params.paymentToken),
erc20TokenAmount: erc20TokenAmount,
fees: fees,
};
switch (params.asset.schema) {
case types_1.AssetSchema.ERC721:
order.nft = params.asset.address.toLowerCase();
order.nftId = ethers_1.BigNumber.from(params.asset.id).toString();
break;
case types_1.AssetSchema.ERC1155:
order.erc1155Token = params.asset.address.toLowerCase();
order.erc1155TokenId = ethers_1.BigNumber.from(params.asset.id).toString();
order.erc1155TokenAmount = ethers_1.BigNumber.from(params.quantity).toString();
break;
default:
throw Error("createSellOrder failed, unsupported schema : " + params.asset.schema);
}
await this.checkAndApproveSellOrder(order, gasParams);
return order;
}
async createBuyOrder(params, gasParams) {
const expiry = getOrderExpiry(params);
const fees = calcFees(params);
const erc20TokenAmount = calcERC20TokenAmount(params, fees);
const paymentToken = params.paymentToken ? params.paymentToken : this.WETH;
const order = {
maker: params.makerAddress.toLowerCase(),
taker: params.takerAddress.toLowerCase(),
expiry: expiry,
nonce: ethers_1.BigNumber.from(params.nonce).toString(),
erc20Token: (0, tokenUtil_1.toContractERC20Token)(paymentToken),
erc20TokenAmount: erc20TokenAmount,
fees: fees,
};
const { tokenId, properties } = getBuyOrderTokenIdAndProperties(params);
switch (params.asset.schema) {
case types_1.AssetSchema.ERC721:
order.nft = params.asset.address.toLowerCase();
order.nftId = tokenId;
order.nftProperties = properties;
break;
case types_1.AssetSchema.ERC1155:
order.erc1155Token = params.asset.address.toLowerCase();
order.erc1155TokenId = tokenId;
order.erc1155TokenAmount = ethers_1.BigNumber.from(params.quantity).toString();
order.erc1155TokenProperties = properties;
break;
default:
throw Error("createBuyOrder failed, unsupported schema : " + params.asset.schema);
}
await this.checkAndApproveBuyOrder(order, gasParams);
return order;
}
async signOrder(order) {
const chainId = this.web3Signer.chainId;
const typedData = (0, orderTypedData_1.getOrderTypedData)(order, chainId);
const signature = await this.web3Signer.signTypedData(order.maker, typedData);
const orderHash = Web3Signer_1.Web3Signer.getOrderHash(typedData);
return {
chainId: chainId,
order: order,
signature: {
signatureType: orderTypes_1.SignatureType.EIP712,
v: signature.v,
r: signature.r,
s: signature.s,
},
orderHash: orderHash,
};
}
async cancelERC1155Orders(signedOrders, gasParams) {
const nonces = [];
for (const signedOrder of signedOrders) {
nonces.push(signedOrder.order.nonce);
}
const elementEx = await this.getElementEx();
const tx = await elementEx.populateTransaction.batchCancelERC1155Orders(nonces);
if (!tx?.data) {
throw Error("cancelOrder failed, populateTransaction error.");
}
const from = await this.web3Signer.getCurrentAccount();
const call = {
from: from,
to: elementEx.address,
data: tx.data,
gasPrice: gasParams.gasPrice,
maxPriorityFeePerGas: gasParams.maxPriorityFeePerGas,
maxFeePerGas: gasParams.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
async cancelAllOrders(gasParams) {
const elementEx = await this.getElementEx();
const tx = await elementEx.populateTransaction.incrementHashNonce();
if (!tx?.data) {
throw Error("cancelAllOrders failed, populateTransaction error.");
}
const from = await this.web3Signer.getCurrentAccount();
const call = {
from: from,
to: elementEx.address,
data: tx.data,
gasPrice: gasParams?.gasPrice,
maxPriorityFeePerGas: gasParams?.maxPriorityFeePerGas,
maxFeePerGas: gasParams?.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
async getElementEx() {
const signer = await this.web3Signer.getSigner();
return (0, contracts_1.getElementExContract)(this.web3Signer.chainId, signer);
}
async getHelper() {
const signer = await this.web3Signer.getSigner();
return (0, contracts_1.getHelperContract)(this.web3Signer.chainId, signer);
}
async checkAndApproveSellOrder(order, gasParams) {
const isERC721Order = order["nft"] != null;
const helper = await this.getHelper();
const elementEx = await this.getElementEx();
const r = isERC721Order
? await helper.checkERC721SellOrder(order, types_1.NULL_ADDRESS)
: await helper.checkERC1155SellOrder(order, types_1.NULL_ADDRESS, "0");
order.hashNonce = r.info?.hashNonce?.toString();
if (r.info.success) {
return;
}
if (!r.info.makerCheck) {
throw Error("createSellOrder failed, makerCheck error.");
}
if (!r.info.takerCheck) {
throw Error("createSellOrder failed, takerCheck error.");
}
if (!r.info.listingTimeCheck) {
throw Error("createSellOrder failed, listingTimeCheck error.");
}
if (!r.info.expireTimeCheck) {
throw Error("createSellOrder failed, expireTimeCheck error.");
}
if (!r.info.extraCheck) {
throw Error("createSellOrder failed, extraCheck error.");
}
if (!r.info.feesCheck) {
throw Error("createSellOrder failed, feesCheck error.");
}
if (!r.info.nonceCheck) {
throw Error("createSellOrder failed, nonceCheck error, please try again.");
}
if (!r.info.erc20AddressCheck) {
throw Error("createSellOrder failed, erc20AddressCheck error.");
}
if (isERC721Order) {
if (!r.info.erc721OwnerCheck) {
throw Error(`createSellOrder, erc721OwnerCheck failed, make sure account(order.maker) is owner of assetId(order["nftId"]).`);
}
if (!r.info.erc721ApprovedCheck) {
console.log("start approveERC721, ERC721Address =", order["nft"]);
const tx = await this.web3Signer.approveERC721Proxy(order.maker, order["nft"], elementEx.address, gasParams);
console.log("approveERC721, tx.hash", tx.hash);
await tx.wait();
console.log("approveERC721, completed.");
}
}
else {
if (order["erc1155TokenAmount"] == null ||
ethers_1.BigNumber.from(order["erc1155TokenAmount"]).lt("1")) {
throw Error("createSellOrder, quantityCheck failed, erc1155 should set quantity.");
}
if (!r.info.remainingAmountCheck) {
throw Error("createSellOrder, remainingAmountCheck failed, please try again.");
}
if (!r.info.erc1155BalanceCheck) {
throw Error(`createSellOrder, erc1155BalanceCheck failed, account(order.maker), require erc1155Balance >= quantity`);
}
if (!r.info.erc1155ApprovedCheck) {
console.log("start approveERC1155, ERC1155Address =", order["erc1155Token"]);
const tx = await this.web3Signer.approveERC1155Proxy(order.maker, order["erc1155Token"], elementEx.address, gasParams);
console.log("approveERC1155, tx.hash", tx.hash);
await tx.wait();
console.log("approveERC1155, completed.");
}
}
}
async checkAndApproveBuyOrder(order, gasParams) {
const isERC721Order = "nft" in order;
const helper = await this.getHelper();
const elementEx = await this.getElementEx();
const r = isERC721Order
? await helper.checkERC721BuyOrder(order, types_1.NULL_ADDRESS, "0")
: await helper.checkERC1155BuyOrder(order, types_1.NULL_ADDRESS, "0", "0");
order.hashNonce = r.info?.hashNonce?.toString();
if (r.info.success) {
return;
}
if (!r.info.makerCheck) {
throw Error("createBuyOrder, makerCheck failed.");
}
if (!r.info.takerCheck) {
throw Error("createBuyOrder, takerCheck failed.");
}
if (!r.info.listingTimeCheck) {
throw Error("createBuyOrder, listingTimeCheck failed.");
}
if (!r.info.expireTimeCheck) {
throw Error("createBuyOrder, expireTimeCheck failed.");
}
if (!r.info.feesCheck) {
throw Error("createBuyOrder, feesCheck failed.");
}
if (!r.info.nonceCheck) {
throw Error("createBuyOrder, nonceCheck failed, please try again.");
}
if (!r.info.erc20AddressCheck) {
throw Error("createBuyOrder, erc20AddressCheck failed, should be ERC20 address, can not be native address.");
}
if (!r.info.propertiesCheck) {
throw Error("createBuyOrder, propertiesCheck failed.");
}
if (!isERC721Order) {
if (order["erc1155TokenAmount"] == null ||
ethers_1.BigNumber.from(order["erc1155TokenAmount"]).lt("1")) {
throw Error("createBuyOrder, quantityCheck failed, quantity: " +
order["erc1155TokenAmount"]);
}
if (!r.info.remainingAmountCheck) {
throw Error("createBuyOrder, remainingAmountCheck failed, please try again.");
}
}
if (!r.info.erc20BalanceCheck) {
throw Error(`createBuyOrder, erc20BalanceCheck failed, make sure accountorder.maker have enough balance of erc20Token(order.erc20Token).`);
}
if (!r.info.erc20AllowanceCheck &&
order.erc20Token.toLowerCase() != types_1.ETH_TOKEN_ADDRESS) {
console.log("start approveERC20, ERC20Address =", order.erc20Token);
const tx = await this.web3Signer.approveERC20Proxy(order.maker, order.erc20Token, elementEx.address, gasParams);
console.log("approveERC20, tx.hash", tx.hash);
await tx.wait(1);
console.log("approveERC20, completed.");
}
}
}
exports.OrderManager = OrderManager;
function calcFees(params) {
const fees = [];
const totalAmount = ethers_1.BigNumber.from(params.startTokenAmount);
if (params.platformFeePoint && params.platformFeeAddress) {
fees.push({
recipient: params.platformFeeAddress,
amount: totalAmount.mul(params.platformFeePoint).div(10000).toString(),
feeData: "0x",
});
}
if (params.royaltyFeePoint && params.royaltyFeeAddress) {
fees.push({
recipient: params.royaltyFeeAddress,
amount: totalAmount.mul(params.royaltyFeePoint).div(10000).toString(),
feeData: "0x",
});
}
return fees;
}
function calcERC20TokenAmount(params, fees) {
let amount = ethers_1.BigNumber.from(params.startTokenAmount);
for (const fee of fees) {
amount = amount.sub(fee.amount);
}
return amount.toString();
}
function getOrderExpiry(params) {
if (params.saleKind == null || params.saleKind == types_1.SaleKind.FixedPrice) {
const { listingTime, expirationTime } = getOrderTimeOfFixedPrice(params);
// saleKind (4bit) + oracleSignature(4bit) + reserved(152bit) + extra(32bit) + listingTime(32bit) + expiryTime(32bit) = 256bit
return (0, bitsUtil_1.encodeBits)([
[0, 4],
[params.oracleSignature, 4],
[0, 152],
[0, 32],
[listingTime, 32],
[expirationTime, 32],
]);
}
throw Error("createOrder failed, unsupported saleKind : " + params.saleKind);
}
function getOrderTimeOfFixedPrice(params) {
const now = Math.floor(Date.now() / 1000);
let listingTime;
if (params.listingTime) {
listingTime = params.listingTime;
if (listingTime > now + orderTypes_1.MAX_LISTING_TIME) {
throw Error("makeOrder failed, require listingTime <= now + 1 year.");
}
if (listingTime < now - 1800) {
throw Error("makeOrder failed, listingTime >= now - 30 minute.");
}
}
else {
listingTime = now - 60;
}
let expirationTime;
if (params.expirationTime != null) {
expirationTime = params.expirationTime;
if (expirationTime < Math.max(listingTime, now)) {
throw Error("makeOrder failed, require expirationTime >= Math.max(listingTime, now).");
}
if (expirationTime > Math.max(listingTime, now) + orderTypes_1.MAX_EXPIRATION_TIME) {
throw Error("makeOrder failed, require expirationTime <= Math.max(listingTime, now) + 1 year.");
}
}
else {
expirationTime = Math.max(listingTime, now) + orderTypes_1.DEFAULT_EXPIRATION_TIME;
}
return { listingTime, expirationTime };
}
function getBuyOrderTokenIdAndProperties(params) {
if (params.asset.id == null) {
return {
tokenId: "0",
properties: [
{
propertyValidator: types_1.NULL_ADDRESS,
propertyData: "0x",
},
],
};
}
else {
return {
tokenId: ethers_1.BigNumber.from(params.asset.id).toString(),
properties: [],
};
}
}
//# sourceMappingURL=orderManager.js.map
FILE:scripts/lib/code/src/element/order/orderTypedData.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOrderTypedData = getOrderTypedData;
const config_1 = require("../../contracts/config");
const FEE_ABI = [
{ type: 'address', name: 'recipient' },
{ type: 'uint256', name: 'amount' },
{ type: 'bytes', name: 'feeData' }
];
const PROPERTY_ABI = [
{ type: 'address', name: 'propertyValidator' },
{ type: 'bytes', name: 'propertyData' }
];
// ERC721Order EIP712 information
const STRUCT_ERC721_SELL_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'nft' },
{ type: 'uint256', name: 'nftId' },
{ type: 'uint256', name: 'hashNonce' }
];
const STRUCT_ERC721_BUY_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'nft' },
{ type: 'uint256', name: 'nftId' },
{ type: 'Property[]', name: 'nftProperties' },
{ type: 'uint256', name: 'hashNonce' }
];
// ERC1155Order EIP712 information
const STRUCT_ERC1155_SELL_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'erc1155Token' },
{ type: 'uint256', name: 'erc1155TokenId' },
{ type: 'uint128', name: 'erc1155TokenAmount' },
{ type: 'uint256', name: 'hashNonce' }
];
const STRUCT_ERC1155_BUY_ORDER_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'address', name: 'taker' },
{ type: 'uint256', name: 'expiry' },
{ type: 'uint256', name: 'nonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'Fee[]', name: 'fees' },
{ type: 'address', name: 'erc1155Token' },
{ type: 'uint256', name: 'erc1155TokenId' },
{ type: 'Property[]', name: 'erc1155TokenProperties' },
{ type: 'uint128', name: 'erc1155TokenAmount' },
{ type: 'uint256', name: 'hashNonce' }
];
function getOrderTypedData(order, chainId) {
if (order['nft'] != undefined) {
return getERC721TypedData(order, chainId);
}
else {
return getERC1155TypedData(order, chainId);
}
}
function getERC721TypedData(order, chainId) {
if (order.nftProperties == null) {
// ERC721SellOrder
return {
types: {
['NFTSellOrder']: STRUCT_ERC721_SELL_ORDER_ABI,
['Fee']: FEE_ABI
},
domain: getDomain(chainId),
primaryType: 'NFTSellOrder',
message: order
};
}
else {
// ERC721BuyOrder
return {
types: {
['NFTBuyOrder']: STRUCT_ERC721_BUY_ORDER_ABI,
['Fee']: FEE_ABI,
['Property']: PROPERTY_ABI
},
domain: getDomain(chainId),
primaryType: 'NFTBuyOrder',
message: order
};
}
}
function getERC1155TypedData(order, chainId) {
if (order.erc1155TokenProperties == undefined) {
// ERC1155SellOrder
return {
types: {
['ERC1155SellOrder']: STRUCT_ERC1155_SELL_ORDER_ABI,
['Fee']: FEE_ABI
},
domain: getDomain(chainId),
primaryType: 'ERC1155SellOrder',
message: order
};
}
else {
// ERC1155BuyOrder
return {
types: {
['ERC1155BuyOrder']: STRUCT_ERC1155_BUY_ORDER_ABI,
['Fee']: FEE_ABI,
['Property']: PROPERTY_ABI
},
domain: getDomain(chainId),
primaryType: 'ERC1155BuyOrder',
message: order
};
}
}
function getDomain(chainId) {
return {
name: 'ElementEx',
version: '1.0.0',
chainId: chainId,
verifyingContract: config_1.CONTRACTS_ADDRESSES[chainId].ElementEx.toLowerCase()
};
}
//# sourceMappingURL=orderTypedData.js.map
FILE:scripts/lib/code/src/element/order/orderTypes.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignatureType = exports.MAX_LISTING_TIME = exports.MAX_EXPIRATION_TIME = exports.DEFAULT_EXPIRATION_TIME = void 0;
exports.DEFAULT_EXPIRATION_TIME = (7 * 86400);
exports.MAX_EXPIRATION_TIME = (365 * 86400);
exports.MAX_LISTING_TIME = (365 * 86400);
var SignatureType;
(function (SignatureType) {
SignatureType[SignatureType["EIP712"] = 0] = "EIP712";
SignatureType[SignatureType["PRESIGNED"] = 1] = "PRESIGNED";
})(SignatureType || (exports.SignatureType = SignatureType = {}));
//# sourceMappingURL=orderTypes.js.map
FILE:scripts/lib/code/src/element/batchSignedOrder/batchSignedOrderManager.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BatchSignedOrderManager = exports.maxBasicERC20Amount = exports.maxERC20Amount = exports.maxBasicNftId = void 0;
exports.getSucceedList = getSucceedList;
const Web3Signer_1 = require("../../signer/Web3Signer");
const contracts_1 = require("../../contracts/contracts");
const ethers_1 = require("ethers");
const types_1 = require("../../types/types");
const orderTypes_1 = require("../order/orderTypes");
const chainUtil_1 = require("../../util/chainUtil");
const tokenUtil_1 = require("../../util/tokenUtil");
const batchSignedTypedData_1 = require("./batchSignedTypedData");
const openApi_1 = require("../../api/openApi");
const numberUtil_1 = require("../../util/numberUtil");
exports.maxBasicNftId = ethers_1.BigNumber.from('0xffffffffffffffffffffffffffffffffffffffff');
exports.maxERC20Amount = ethers_1.BigNumber.from('0xffffffffffffffffffffffffffffffffffffffff');
exports.maxBasicERC20Amount = ethers_1.BigNumber.from('0xffffffffffffffffffffffff');
class BatchSignedOrderManager {
constructor(web3Signer, apiOption) {
this.web3Signer = web3Signer;
this.apiOption = apiOption;
}
async createOrders(params, counter) {
const fees = await this.queryFees(params);
const platformFeeRecipient = getPlatformFeeRecipient(fees);
const chain = (0, chainUtil_1.getChain)(this.web3Signer.chainId);
const maker = await this.web3Signer.getCurrentAccount();
const paymentToken = (0, tokenUtil_1.toStandardERC20Token)(params.paymentToken);
const { listingTime, expirationTime } = getOrderTime(params);
const elementEx = await this.getElementEx();
const hashNonce = (counter != null) ? counter : await elementEx.getHashNonce(maker);
const list = getOrders(params.items);
const orders = [];
let error;
for (const order of list) {
try {
const nonce = await (0, openApi_1.queryNonce)({
maker: maker,
schema: types_1.AssetSchema.ERC721,
count: order.itemCount
}, this.apiOption);
const oracleSignature = await (0, openApi_1.queryOracleSignature)(this.apiOption);
setCollectionFees(order.basicCollections, fees);
setCollectionFees(order.collections, fees);
orders.push({
exchange: elementEx.address.toLowerCase(),
maker: maker.toLowerCase(),
listingTime: listingTime,
expirationTime: expirationTime,
startNonce: nonce,
paymentToken: paymentToken,
platformFeeRecipient: platformFeeRecipient,
basicCollections: order.basicCollections,
collections: order.collections,
hashNonce: hashNonce.toString(),
oracleSignature,
chain: chain
});
}
catch (e) {
error = e;
}
}
if (orders.length == 0) {
throw error;
}
return orders;
}
async approveAndGetCounter(params) {
checkSellOrdersParams(params);
const set = new Set;
for (const item of params.items) {
set.add(item.erc721TokenAddress.toLowerCase());
}
const elementEx = await this.getElementEx();
const helper = await this.getHelper();
const list = [];
for (const value of set.values()) {
list.push({
tokenType: 0,
tokenAddress: value,
operator: elementEx.address
});
}
const owner = await this.web3Signer.getCurrentAccount();
const r = await helper.getSDKApprovalsAndCounter(owner, list);
for (let i = 0; i < list.length; i++) {
if (r.approvals[i].eq(0)) {
console.log('start approveERC721, ERC721Address =', list[i].tokenAddress);
const tx = await this.web3Signer.approveERC721Proxy(owner, list[i].tokenAddress, elementEx.address, params);
console.log('approveERC721, tx.hash', tx.hash);
const receipt = await tx.wait(1);
console.log('approveERC721, completed receipt', JSON.stringify(receipt));
console.log('approveERC721, completed gasUsed =', (0, numberUtil_1.toString)(receipt.gasUsed));
}
}
return parseInt(r.elementCounter);
}
async signOrder(order) {
const typedData = (0, batchSignedTypedData_1.getTypedData)(order, this.web3Signer.chainId);
const sign = await this.web3Signer.signTypedData(order.maker, typedData);
const o = order;
o.v = sign.v;
o.r = sign.r;
o.s = sign.s;
o.hash = Web3Signer_1.Web3Signer.getOrderHash(typedData);
// const r = await this.helper.checkBSERC721Orders(o)
// console.log(JSON.stringify(r))
// console.log(JSON.stringify(o))
return o;
}
async getElementEx() {
const signer = await this.web3Signer.getSigner();
return (0, contracts_1.getElementExContract)(this.web3Signer.chainId, signer);
}
async getHelper() {
const signer = await this.web3Signer.getSigner();
return (0, contracts_1.getHelperContract)(this.web3Signer.chainId, signer);
}
async queryFees(params) {
const addressList = [];
for (const item of params.items) {
const address = item.erc721TokenAddress.toLowerCase();
if (!addressList.includes(address)) {
addressList.push(address);
}
}
const fees = await (0, openApi_1.queryFees)(addressList, this.apiOption);
const map = new Map();
for (const fee of fees) {
map.set(fee.contractAddress.toLowerCase(), fee);
}
return map;
}
}
exports.BatchSignedOrderManager = BatchSignedOrderManager;
function getSucceedList(order, assets) {
if (assets.length == 0) {
return [];
}
const map = new Map;
let nonce = Number(order.startNonce);
for (const collection of order.basicCollections) {
for (const item of collection.items) {
const key = (collection.nftAddress + ',' + item.nftId).toLowerCase();
const value = {
erc20TokenAmount: item.erc20TokenAmount,
nonce: nonce++
};
map.set(key, value);
}
}
for (const collection of order.collections) {
for (const item of collection.items) {
const key = (collection.nftAddress + ',' + item.nftId).toLowerCase();
const value = {
erc20TokenAmount: item.erc20TokenAmount,
nonce: nonce++
};
map.set(key, value);
}
}
const list = [];
for (const asset of assets) {
const assetContract = asset.assetContract?.toString().toLowerCase() || '';
const tokenId = (0, numberUtil_1.toString)(asset.assetTokenId);
const key = assetContract + ',' + tokenId;
const value = map.get(key);
if (value) {
list.push({
contractAddress: assetContract,
tokenId: tokenId,
schema: types_1.AssetSchema.ERC721,
standard: types_1.Standard.ElementEx,
maker: order.maker,
listingTime: order.listingTime,
expirationTime: order.expirationTime,
price: Number(ethers_1.ethers.utils.formatEther(value.erc20TokenAmount)),
paymentToken: order.paymentToken,
saleKind: types_1.SaleKind.BatchSignedERC721Order,
side: types_1.OrderSide.SellOrder,
orderId: asset.orderId
});
}
}
return list;
}
function checkSellOrdersParams(params) {
if (!params.items?.length) {
throw Error(`makeERC721SellOrders failed, items.length error.`);
}
const set = new Set();
for (const item of params.items) {
const key = item.erc721TokenAddress.toLowerCase() + ',' + (0, numberUtil_1.toString)(item.erc721TokenId);
if (set.has(key)) {
throw Error(`makeERC721SellOrders failed, the same asset is not supported, assetAddress(item.erc721TokenAddress, assetId(item.erc721TokenId)).`);
}
set.add(key);
}
}
function setCollectionFees(collections, fees) {
for (const collection of collections) {
const fee = fees.get(collection.nftAddress);
if (fee) {
if (fee.protocolFeeAddress && fee.protocolFeeAddress.toLowerCase() != types_1.NULL_ADDRESS) {
collection.platformFee = fee.protocolFeePoints || 0;
}
if (fee.royaltyFeeAddress && fee.royaltyFeeAddress.toLowerCase() != types_1.NULL_ADDRESS) {
collection.royaltyFee = fee.royaltyFeePoints || 0;
collection.royaltyFeeRecipient = fee.royaltyFeeAddress.toLowerCase();
}
}
if (collection.platformFee < 0 || collection.royaltyFee < 0 || (collection.platformFee + collection.royaltyFee) > 10000) {
throw Error(`makeERC721SellOrders failed, feePoint error, platformFeePoint(collection.platformFee, royaltyFeePoint(collection.royaltyFee)`);
}
}
}
function getPlatformFeeRecipient(fees) {
let platformFeeRecipient;
for (const fee of fees.values()) {
if (fee.protocolFeePoints) {
const protocolFeeAddress = fee.protocolFeeAddress ? fee.protocolFeeAddress.toLowerCase() : types_1.NULL_ADDRESS;
if (platformFeeRecipient) {
if (platformFeeRecipient != protocolFeeAddress) {
throw Error(`check platformFeeRecipient failed, platformFeeRecipient1(platformFeeRecipient), platformFeeRecipient2(protocolFeeAddress)`);
}
}
else {
platformFeeRecipient = protocolFeeAddress;
}
}
}
return platformFeeRecipient ? platformFeeRecipient : types_1.NULL_ADDRESS;
}
function getOrders(items) {
const map = new Map;
for (const item of items) {
if (!item.erc721TokenAddress || item.erc721TokenAddress.toLowerCase() == types_1.NULL_ADDRESS) {
throw Error(`makeERC721SellOrders failed, tokenAddress(item.erc721TokenAddress) error.`);
}
if (item.erc721TokenId == null || item.erc721TokenId === '') {
throw Error(`makeERC721SellOrders failed, tokenId(item.erc721TokenId) error.`);
}
let collection = map.get(item.erc721TokenAddress.toLowerCase());
if (collection == null) {
collection = {
nftAddress: item.erc721TokenAddress.toLowerCase(),
items: [],
isBasic: true
};
map.set(collection.nftAddress, collection);
}
const obj = {
erc20TokenAmount: (0, numberUtil_1.toString)(item.paymentTokenAmount),
nftId: (0, numberUtil_1.toString)(item.erc721TokenId)
};
collection.items.push(obj);
if (collection.isBasic) {
if (exports.maxBasicERC20Amount.lt(obj.erc20TokenAmount) || exports.maxBasicNftId.lt(obj.nftId)) {
collection.isBasic = false;
}
}
if (exports.maxERC20Amount.lt(obj.erc20TokenAmount)) {
throw Error(`makeERC721SellOrders failed, item.paymentTokenAmount(obj.erc20TokenAmount exceed the maxValue(exports.maxERC20Amount.toHexString())).`);
}
}
let point = 0;
let order = null;
const orders = [];
for (const value of map.values()) {
if (isOrderFulled(point, 2, order)) {
point = 0;
order = null;
}
point += 2;
let collection;
const plusPoint = value.isBasic ? 1 : 2;
for (const item of value.items) {
if (isOrderFulled(point, plusPoint, order)) {
point = 2;
order = null;
collection = null;
}
if (order == null) {
order = {
basicCollections: [],
collections: [],
itemCount: 0
};
orders.push(order);
}
if (collection == null) {
collection = {
nftAddress: value.nftAddress,
platformFee: 0,
royaltyFeeRecipient: types_1.NULL_ADDRESS,
royaltyFee: 0,
items: []
};
if (value.isBasic) {
order.basicCollections.push(collection);
}
else {
order.collections.push(collection);
}
}
point += plusPoint;
order.itemCount++;
collection.items.push(item);
}
}
return orders;
}
function isOrderFulled(point, plusPoint, order) {
if (point + plusPoint > 102) {
return true;
}
return order != null && order.itemCount >= 50;
}
function getOrderTime(params) {
const now = Math.floor(Date.now() / 1000);
let listingTime;
if (params.listingTime) {
listingTime = params.listingTime;
if (listingTime > now + orderTypes_1.MAX_LISTING_TIME) {
throw Error('makeERC721SellOrders failed, require listingTime <= now + 1 year.');
}
if (listingTime < (now - 1800)) {
throw Error('makeERC721SellOrders failed, listingTime >= now - 30 minute.');
}
}
else {
listingTime = now - 60;
}
let expirationTime;
if (params.expirationTime != null) {
expirationTime = params.expirationTime;
if (expirationTime < Math.max(listingTime, now)) {
throw Error('makeERC721SellOrders failed, require expirationTime >= Math.max(listingTime, now).');
}
if (expirationTime > Math.max(listingTime, now) + orderTypes_1.MAX_EXPIRATION_TIME) {
throw Error('makeERC721SellOrders failed, require expirationTime <= Math.max(listingTime, now) + 1 year.');
}
}
else {
expirationTime = Math.max(listingTime, now) + orderTypes_1.DEFAULT_EXPIRATION_TIME;
}
return { listingTime, expirationTime };
}
//# sourceMappingURL=batchSignedOrderManager.js.map
FILE:scripts/lib/code/src/element/batchSignedOrder/batchSignedTypedData.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTypedData = getTypedData;
const tokenUtil_1 = require("../../util/tokenUtil");
const bitsUtil_1 = require("../../util/bitsUtil");
const BATCH_SIGNED_ERC721_ORDERS_ABI = [
{ type: 'address', name: 'maker' },
{ type: 'uint256', name: 'listingTime' },
{ type: 'uint256', name: 'expiryTime' },
{ type: 'uint256', name: 'startNonce' },
{ type: 'address', name: 'erc20Token' },
{ type: 'address', name: 'platformFeeRecipient' },
{ type: 'BasicCollection[]', name: 'basicCollections' },
{ type: 'Collection[]', name: 'collections' },
{ type: 'uint256', name: 'hashNonce' }
];
const BASIC_COLLECTION_ABI = [
{ type: 'address', name: 'nftAddress' },
{ type: 'bytes32', name: 'fee' },
{ type: 'bytes32[]', name: 'items' }
];
const COLLECTION_ABI = [
{ type: 'address', name: 'nftAddress' },
{ type: 'bytes32', name: 'fee' },
{ type: 'OrderItem[]', name: 'items' }
];
const ORDER_ITEM_ABI = [
{ type: 'uint256', name: 'erc20TokenAmount' },
{ type: 'uint256', name: 'nftId' }
];
function getTypedData(order, chainId) {
return {
types: {
['BatchSignedERC721Orders']: BATCH_SIGNED_ERC721_ORDERS_ABI,
['BasicCollection']: BASIC_COLLECTION_ABI,
['Collection']: COLLECTION_ABI,
['OrderItem']: ORDER_ITEM_ABI
},
domain: {
name: 'ElementEx',
version: '1.0.0',
chainId: chainId,
verifyingContract: order.exchange
},
primaryType: 'BatchSignedERC721Orders',
message: toStandardOrder(order)
};
}
function toStandardOrder(order) {
return {
maker: order.maker,
listingTime: order.listingTime,
expiryTime: (0, bitsUtil_1.encodeBits)([
[0, 4],
[order.oracleSignature, 4],
[order.expirationTime, 248]
]),
startNonce: order.startNonce,
erc20Token: (0, tokenUtil_1.toContractERC20Token)(order.paymentToken),
platformFeeRecipient: order.platformFeeRecipient,
basicCollections: toStandardBasicCollections(order),
collections: toStandardCollections(order),
hashNonce: order.hashNonce
};
}
function toStandardBasicCollections(order) {
const basicCollections = [];
if (order.basicCollections != null) {
for (const collection of order.basicCollections) {
const items = [];
if (collection.items) {
for (const item of collection.items) {
/// @param item [96 bits(erc20TokenAmount) + 160 bits(nftId)].
items.push((0, bitsUtil_1.encodeBits)([
[item.erc20TokenAmount, 96],
[item.nftId, 160]
]));
}
}
basicCollections.push({
nftAddress: collection.nftAddress,
/// @param fee [16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)].
fee: (0, bitsUtil_1.encodeBits)([
[0, 64],
[collection.platformFee, 16],
[collection.royaltyFee, 16],
[collection.royaltyFeeRecipient, 160]
]),
items: items
});
}
}
return basicCollections;
}
function toStandardCollections(order) {
const collections = [];
if (order.collections != null) {
for (const collection of order.collections) {
const items = [];
if (collection.items) {
items.push(...collection.items);
}
collections.push({
nftAddress: collection.nftAddress,
/// @param fee [16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)].
fee: (0, bitsUtil_1.encodeBits)([
[0, 64],
[collection.platformFee, 16],
[collection.royaltyFee, 16],
[collection.royaltyFeeRecipient, 160]
]),
items: items
});
}
}
return collections;
}
//# sourceMappingURL=batchSignedTypedData.js.map
FILE:scripts/lib/code/src/element/batchSignedOrder/batchSignedTypes.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=batchSignedTypes.js.map
FILE:scripts/lib/code/src/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ElementSDK = void 0;
const chainUtil_1 = require("./util/chainUtil");
const openApi_1 = require("./api/openApi");
const types_1 = require("./types/types");
const Web3Signer_1 = require("./signer/Web3Signer");
const batchSignedOrderManager_1 = require("./element/batchSignedOrder/batchSignedOrderManager");
const orderManager_1 = require("./element/order/orderManager");
const orderConverter_1 = require("./element/order/orderConverter");
const numberUtil_1 = require("./util/numberUtil");
const receiptUtil_1 = require("./util/receiptUtil");
const assetUtil_1 = require("./util/assetUtil");
const ethers_1 = require("ethers");
const tokenUtil_1 = require("./util/tokenUtil");
class ElementSDK {
constructor(config) {
this.isTestnet = false;
if (config.isTestnet != null) {
this.isTestnet = config.isTestnet;
}
this.chainId = (0, chainUtil_1.getChainId)(config.networkName, this.isTestnet);
this.apiOption = {
chain: config.networkName,
isTestnet: this.isTestnet,
apiKey: config.apiKey,
};
this.web3Signer = new Web3Signer_1.Web3Signer(config.signer, this.chainId);
this.batchOrderManager = new batchSignedOrderManager_1.BatchSignedOrderManager(this.web3Signer, this.apiOption);
this.orderManager = new orderManager_1.OrderManager(this.web3Signer);
}
async makeERC721SellOrders(params) {
let error;
const succeedList = [];
const failedList = [];
// 1. setApproveForAll
const counter = await this.batchOrderManager.approveAndGetCounter(params);
// 2. create orders
const orders = await this.batchOrderManager.createOrders(params, counter);
for (const order of orders) {
try {
// 3. sign order
const signedOrder = await this.batchOrderManager.signOrder(order);
// 4. post order
const r = await (0, openApi_1.postBatchSignedERC721SellOrder)(signedOrder, this.apiOption);
succeedList.push(...(0, batchSignedOrderManager_1.getSucceedList)(signedOrder, r.successList));
failedList.push(...r.failList);
}
catch (e) {
error = e;
}
}
if (succeedList.length == 0 && failedList.length == 0) {
throw error;
}
return {
succeedList: succeedList,
failedList: failedList,
};
}
async makeSellOrder(params) {
if (params.assetId == null) {
throw Error("createSellOrder failed, asset.id is undefined.");
}
if ((!params.assetSchema || params.assetSchema.toLowerCase() == "erc721") &&
(!params.takerAddress ||
params.takerAddress.toLowerCase() == types_1.NULL_ADDRESS)) {
const r = await this.makeERC721SellOrders({
listingTime: params.listingTime,
expirationTime: params.expirationTime,
paymentToken: params.paymentToken,
items: [
{
erc721TokenId: (0, numberUtil_1.toString)(params.assetId),
erc721TokenAddress: params.assetAddress,
paymentTokenAmount: (0, numberUtil_1.toString)(params.paymentTokenAmount),
},
],
gasPrice: params.gasPrice,
maxFeePerGas: params.maxFeePerGas,
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
});
if (!r.succeedList?.length) {
const e = r.failedList?.length ? r.failedList[0].errorDetail : "";
throw Error("createSellOrder failed, " + e);
}
return r.succeedList[0];
}
return await this.makeOrder(params, false);
}
async makeBuyOrder(params) {
return await this.makeOrder(params, true);
}
async fillOrder(params) {
if (params.order.standard?.toString().toLowerCase() != types_1.Standard.ElementEx) {
throw Error(`fillOrder failed, standard(params.order.standard) is not supported`);
}
const account = await this.web3Signer.getCurrentAccount();
const takeCount = params.quantity ? Number(params.quantity) || 1 : 1;
if (params.order.side === types_1.OrderSide.SellOrder ||
params.order.side == "sell") {
if ((0, tokenUtil_1.toStandardERC20Token)(params.order.paymentToken) !== types_1.NULL_ADDRESS) {
const providedDecimals = Number(params.order.paymentTokenDecimals);
if (!Number.isFinite(providedDecimals)) {
throw Error("fillOrder failed, ERC20-priced orders require `paymentTokenDecimals`. Look it up from the payment token reference and pass it explicitly.");
}
const decimals = providedDecimals;
const payValue = takeCount * Number(params.order.price);
const value = ethers_1.ethers.utils.parseUnits(payValue.toString(), decimals);
console.log("approve: " + JSON.stringify(params), JSON.stringify(value));
await (0, assetUtil_1.approveERC20)(this.web3Signer, params.order.paymentToken, value, params);
}
}
else {
await (0, assetUtil_1.setApproveForAll)(this.web3Signer, params.order.contractAddress, params);
}
if (params.order.saleKind === types_1.SaleKind.ContractOffer ||
params.order.saleKind === types_1.SaleKind.BatchOfferERC721s) {
if (!params.assetId?.toString()) {
throw Error(`fillOrder failed, Collection-Based Offer requires the \`assetId\`.`);
}
}
const tradeData = await (0, openApi_1.queryTradeData)(account, [
{
orderId: params.order.orderId,
takeCount,
tokenId: params.assetId?.toString(),
},
], this.apiOption);
const call = {
from: account,
to: tradeData.to,
value: tradeData.value,
data: tradeData.data,
gasPrice: params.gasPrice,
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
maxFeePerGas: params.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
async batchBuyWithETH(params) {
const taker = await this.web3Signer.getCurrentAccount();
const list = this.toOrderIdList(params.orders, params.quantities);
const tradeData = await (0, openApi_1.queryTradeData)(taker, list, this.apiOption);
const call = {
from: taker,
to: tradeData.to,
value: tradeData.value,
data: tradeData.data,
gasPrice: params.gasPrice,
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
maxFeePerGas: params.maxFeePerGas,
};
return this.web3Signer.ethSend(call);
}
async encodeTradeData(params) {
let taker = params.taker;
if (taker == null || taker == "" || taker.toLowerCase() == types_1.NULL_ADDRESS) {
taker = await this.web3Signer.getCurrentAccount();
}
const list = this.toOrderIdList(params.orders, params.quantities, params.tokenIds);
const tradeData = await (0, openApi_1.queryTradeData)(taker, list, this.apiOption);
return {
toContract: tradeData.to,
payableValue: tradeData.value,
data: tradeData.data,
flags: tradeData.flags,
};
}
getBoughtAssets(receipt) {
return (0, receiptUtil_1.getBoughtAssets)(receipt);
}
async cancelOrder(params) {
const account = await this.web3Signer.getCurrentAccount();
if (params.order?.maker?.toLowerCase() != account.toLowerCase()) {
throw Error(`cancelOrder failed, account mismatch, order.maker(params.order?.maker), account(account).`);
}
const signedOrder = JSON.parse(params.order.exchangeData);
if (params.order.standard?.toString().toLowerCase() == types_1.Standard.ElementEx) {
if (params.order.schema.toLowerCase() == types_1.AssetSchema.ERC721.toLowerCase()) {
return this.orderManager.cancelERC721Orders([signedOrder], params);
}
else if (params.order.schema.toLowerCase() == types_1.AssetSchema.ERC1155.toLowerCase()) {
return this.orderManager.cancelERC1155Orders([signedOrder], params);
}
else {
throw Error("cancelOrder failed, unsupported schema : " + params.order.schema);
}
}
else {
throw Error("cancelOrder failed, unsupported standard : " + params.order.standard);
}
}
async cancelOrders(params) {
if (!params.orders?.length) {
throw Error(`cancelOrders failed, orders?.length error.`);
}
const account = await this.web3Signer.getCurrentAccount();
params.orders.forEach((value, index, array) => {
if (account.toLowerCase() != value.maker?.toLowerCase()) {
throw Error(`cancelOrders failed, account mismatch, index=(index), order.maker(value.maker), account(account).`);
}
});
const elementERC721Orders = [];
const elementERC1155Orders = [];
const elementERC721SignedOrders = [];
const elementERC1155SignedOrders = [];
for (const order of params.orders) {
if (order.exchangeData && order.standard) {
const signedOrder = JSON.parse(order.exchangeData);
if (order.standard.toLowerCase() == types_1.Standard.ElementEx) {
if (order.schema?.toLowerCase() == types_1.AssetSchema.ERC721.toLowerCase()) {
elementERC721Orders.push(order);
elementERC721SignedOrders.push(signedOrder);
}
else if (order.schema?.toLowerCase() == types_1.AssetSchema.ERC1155.toLowerCase()) {
elementERC1155Orders.push(order);
elementERC1155SignedOrders.push(signedOrder);
}
}
}
}
const succeedTransactions = [];
if (elementERC721Orders.length > 0) {
const tx = await this.orderManager.cancelERC721Orders(elementERC721SignedOrders, params);
succeedTransactions.push({
orders: elementERC721Orders,
transaction: tx,
});
}
if (elementERC1155Orders.length > 0) {
try {
const tx = await this.orderManager.cancelERC1155Orders(elementERC1155SignedOrders, params);
succeedTransactions.push({
orders: elementERC1155Orders,
transaction: tx,
});
}
catch (e) {
if (succeedTransactions.length == 0) {
throw e;
}
}
}
if (succeedTransactions.length == 0) {
throw Error("cancelOrders failed.");
}
return { succeedTransactions: succeedTransactions };
}
async cancelAllOrdersForSigner(params) {
if (params?.standard?.toLowerCase() == types_1.Standard.ElementEx ||
!params?.standard) {
return this.orderManager.cancelAllOrders(params);
}
else {
throw Error(`cancelAllOrders failed`);
}
}
async queryOrders(query) {
return await (0, openApi_1.queryOrders)(query, this.apiOption);
}
async queryAccountOrders(query) {
return await (0, openApi_1.queryAccountOrders)(query, this.apiOption);
}
toOrderIdList(orders, quantities, tokenIds) {
const list = [];
for (let i = 0; i < orders.length; i++) {
let takeCount = 1;
if (quantities?.length && i < quantities?.length) {
takeCount = Number(quantities[i]) || 1;
}
let tokenId;
if (tokenIds?.length && i < tokenIds.length) {
tokenId = tokenIds[i]?.toString();
}
else {
if (orders[i].saleKind === types_1.SaleKind.ContractOffer ||
orders[i].saleKind === types_1.SaleKind.BatchOfferERC721s) {
throw Error(`orders[i] error, the collection-based offer requires the \`assetId\``);
}
}
list.push({
orderId: orders[i].orderId,
takeCount,
tokenId,
});
}
return list;
}
async makeOrder(params, isBuyOrder) {
const schema = params.assetSchema || types_1.AssetSchema.ERC721;
if (schema.toLowerCase() != "erc721" && schema.toLowerCase() != "erc1155") {
throw Error("makeOrder failed, unsupported schema : " + schema);
}
const assetId = (0, numberUtil_1.toString)(params.assetId) || undefined;
const accountAddress = await this.web3Signer.getCurrentAccount();
const takerAddress = params.takerAddress
? params.takerAddress.toLowerCase()
: types_1.NULL_ADDRESS;
// 1. query nonce
const nonce = await (0, openApi_1.queryNonce)({
maker: accountAddress,
schema: schema,
count: 1,
}, this.apiOption);
// 2. query oracleSignature flag
const oracleSignature = await (0, openApi_1.queryOracleSignature)(this.apiOption);
// 3. queryFees
let platformFeePoint, platformFeeAddress, royaltyFeePoint, royaltyFeeAddress;
if (takerAddress === types_1.NULL_ADDRESS) {
const fees = await (0, openApi_1.queryFees)([params.assetAddress], this.apiOption);
if (fees.length > 0) {
platformFeePoint = fees[0].protocolFeePoints;
platformFeeAddress = fees[0].protocolFeeAddress;
royaltyFeePoint = fees[0].royaltyFeePoints;
royaltyFeeAddress = fees[0].royaltyFeeAddress;
}
}
// 4. create order
const quantity = params.quantity != null ? (0, numberUtil_1.toString)(params.quantity) : undefined;
const orderParams = {
makerAddress: accountAddress,
takerAddress,
asset: {
id: assetId,
address: params.assetAddress,
schema: schema.toString().toUpperCase(),
},
quantity: quantity,
paymentToken: params.paymentToken,
startTokenAmount: (0, numberUtil_1.toString)(params.paymentTokenAmount),
platformFeePoint: platformFeePoint ?? 0,
platformFeeAddress: platformFeeAddress,
royaltyFeePoint: royaltyFeePoint ?? 0,
royaltyFeeAddress: royaltyFeeAddress,
listingTime: (0, numberUtil_1.toNumber)(params.listingTime),
expirationTime: (0, numberUtil_1.toNumber)(params.expirationTime),
nonce: nonce.toString(),
saleKind: types_1.SaleKind.FixedPrice,
oracleSignature,
};
const order = isBuyOrder
? await this.orderManager.createBuyOrder(orderParams, params)
: await this.orderManager.createSellOrder(orderParams, params);
console.log(order);
// 4. sign order
const signedOrder = await this.orderManager.signOrder(order);
// 5. post order
const request = (0, orderConverter_1.toOrderRequest)(signedOrder);
const response = await (0, openApi_1.postOrder)(request, this.apiOption);
return (0, orderConverter_1.toOrderInformation)(request, response.orderId);
}
async transferERC721(tokenAddress, tokenId, toAddress) {
return (0, assetUtil_1.transferERC721)(this.web3Signer, tokenAddress, tokenId, toAddress);
}
async transferERC1155(tokenAddress, tokenId, toAddress, quantity) {
return (0, assetUtil_1.transferERC1155)(this.web3Signer, tokenAddress, tokenId, toAddress, quantity);
}
}
exports.ElementSDK = ElementSDK;
//# sourceMappingURL=index.js.map
FILE:scripts/lib/code/src/api/openApi.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.postOrder = postOrder;
exports.postBatchSignedERC721SellOrder = postBatchSignedERC721SellOrder;
exports.queryTradeData = queryTradeData;
exports.queryNonce = queryNonce;
exports.queryOracleSignature = queryOracleSignature;
exports.queryFees = queryFees;
exports.queryOrders = queryOrders;
exports.queryAccountOrders = queryAccountOrders;
const axios_1 = __importDefault(require("axios"));
const openApiTypes_1 = require("./openApiTypes");
const instance = axios_1.default.create();
async function postOrder(order, option, retries = 1) {
let r;
try {
console.log("Wait for postOrder.");
r = await instance({
method: "post",
url: toUrl("/openapi/v1/orders/post", option),
headers: { "x-api-key": option.apiKey },
data: order,
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("postOrder failed, " + e + ", now try again.");
await sleep(1000);
return postOrder(order, option, retries - 1);
}
throw Error(`postOrder failed, e, order: JSON.stringify(order)`);
}
if (r.data?.code !== 0) {
throw Error(`postOrder failed, r.data?.code, r.data?.msg, JSON.stringify(order)`);
}
console.log("postOrder completed.");
return r.data.data;
}
async function postBatchSignedERC721SellOrder(order, option, retries = 1) {
let r;
try {
console.log("Wait for postBatchOrder.");
r = await instance({
method: "post",
url: toUrl("/openapi/v1/orders/postBatch", option),
headers: { "x-api-key": option.apiKey },
data: order,
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("postBatchOrder failed, " + e + ", now try again.");
await sleep(1000);
return postBatchSignedERC721SellOrder(order, option, retries - 1);
}
throw Error(`postBatchOrder failed, e, order: order`);
}
if (r.data?.code === 0 && r.data?.data) {
console.log("postBatchOrder completed.");
return {
successList: r.data.data.successList || [],
failList: r.data.data.failList || [],
};
}
throw Error(`postBatchOrder failed, r.data?.code, r.data?.msg, JSON.stringify(order)`);
}
async function queryTradeData(account, list, option, retries = 1) {
let r;
try {
r = await instance({
method: "post",
url: toUrl("/openapi/v1/orders/encodeTradeDataByOrderId", option),
headers: { "x-api-key": option.apiKey },
data: {
chain: option.chain,
taker: account.toLowerCase(),
orderIdList: list,
},
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("encodeTradeData failed, " + e + ", now try again.");
await sleep(1000);
return queryTradeData(account, list, option, retries - 1);
}
throw Error(`encodeTradeData failed, e`);
}
if (r.data?.code === 0 && r.data?.data) {
return r.data?.data;
}
throw Error(`encodeTradeData failed, r.data?.code, r.data?.msg`);
}
async function queryNonce(query, option, retries = 1) {
let r;
try {
const url = toUrl(`/openapi/v1/orders/nonce?chain=option.chain`, option) +
toKeyVal("maker", query) +
toKeyVal("exchange", query) +
toKeyVal("schema", query) +
toKeyVal("count", query);
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryNonce failed, " + e + ", now try again.");
await sleep(1000);
return queryNonce(query, option, retries - 1);
}
throw Error("queryNonce failed, " + e);
}
if (r.data?.code === 0 && r.data?.data?.nonce != null) {
console.log("queryNonce, nonce: " + r.data.data.nonce.toString());
return Number(r.data.data.nonce.toString());
}
throw Error("queryNonce failed, " + r.data?.msg);
}
async function queryOracleSignature(option, retries = 1) {
let r;
try {
const url = toUrl(`/openapi/v1/orders/confData?chain=option.chain`, option);
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: openApiTypes_1.TIME_OUT,
});
if (r.data?.data?.oracleSignature != null) {
console.log("queryOracleSignature success, oracleSignature: " +
r.data.data.oracleSignature);
return Number(r.data.data.oracleSignature);
}
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryOracleSignature failed, " + e + ", now try again.");
await sleep(1000);
return queryOracleSignature(option, retries - 1);
}
}
console.log("queryOracleSignature failed, use default value `0`");
return 0;
}
async function queryFees(contractAddressList, option, retries = 1) {
let r;
try {
r = await instance({
method: "post",
url: toUrl("/openapi/v1/collection/fee", option),
headers: { "x-api-key": option.apiKey },
data: {
chain: option.chain,
data: contractAddressList.map((value) => {
return {
contractAddress: value.toLowerCase(),
};
}),
},
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryFees failed, " + e + ", now try again.");
await sleep(1000);
return queryFees(contractAddressList, option, retries - 1);
}
throw Error("queryFees failed, " + e);
}
if (r.data?.code === 0) {
return r.data?.data?.feeList || [];
}
throw Error("queryFees failed, " + r.data?.msg);
}
async function queryOrders(query, option) {
const url = toUrl(`/openapi/v1/orders/list?chain=option.chain`, option) +
toKeyVal("asset_contract_address", query) +
toTokenIdsKeyVal("token_ids", query) +
toKeyVal("sale_kind", query) +
toKeyVal("side", query) +
toKeyVal("maker", query) +
toKeyVal("taker", query) +
toKeyVal("payment_token", query) +
toKeyVal("order_by", query) +
toKeyVal("direction", query) +
toKeyVal("listed_before", query) +
toKeyVal("listed_after", query) +
toKeyVal("limit", query) +
toKeyVal("offset", query);
let r;
try {
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
throw Error("queryOrders failed, " + e);
}
if (r.data?.code === 0) {
return r.data?.data?.orders || [];
}
throw Error("queryOrders failed, " + r.data?.msg);
}
async function queryAccountOrders(query, option, retries = 1) {
const chain = option.chain;
const normalizedLimit = Number(query.limit ?? 20);
const safeLimit = Number.isFinite(normalizedLimit) && normalizedLimit > 0
? Math.min(normalizedLimit, 50)
: 20;
const url = toUrl(`/openapi/v1/account/orderList?chain=chain`, option) +
toKeyVal("wallet_address", query) +
toKeyVal("contract_address", query) +
toKeyVal("cursor", query) +
`&limit=safeLimit`;
let r;
try {
r = await instance({
method: "get",
url: url,
headers: { "x-api-key": option.apiKey },
timeout: openApiTypes_1.TIME_OUT,
});
}
catch (e) {
if (shouldRetry(e, retries)) {
console.log("queryAccountOrders failed, " + e + ", now try again.");
await sleep(1000);
return queryAccountOrders(query, option, retries - 1);
}
throw Error("queryAccountOrders failed, " + e);
}
if (r.data?.code === 0) {
return r.data?.data || {};
}
throw Error("queryAccountOrders failed, " + r.data?.msg);
}
function toUrl(path, option) {
return openApiTypes_1.API_HOST + path;
}
function sleep(ms) {
return Promise.resolve((resolve) => setTimeout(resolve, ms));
}
function toTokenIdsKeyVal(key, query) {
let val = "";
if (query[key]?.length) {
for (const id of query[key]) {
const idStr = formatVal(id);
if (idStr != "") {
if (val != "") {
val += ",";
}
val += idStr;
}
}
}
return val != "" ? `&key=val` : "";
}
function toKeyVal(key, query) {
const val = formatVal(query[key]);
return val != "" ? `&key=val` : "";
}
function formatVal(value) {
return value != null ? value.toString().toLowerCase() : "";
}
function shouldRetry(error, retries) {
if (retries > 0) {
if (error?.message?.toString().startsWith("timeout of")) {
return true;
}
if (error?.response) {
const status = error?.response.status;
return (status == 403 ||
status == 429 ||
status == 500 ||
status == 502 ||
status == 503 ||
status == 504);
}
}
return false;
}
//# sourceMappingURL=openApi.js.map
FILE:scripts/lib/code/src/api/openApiTypes.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TIME_OUT = exports.API_HOST = void 0;
exports.API_HOST = "https://api.element.market";
exports.TIME_OUT = 15000;
//# sourceMappingURL=openApiTypes.js.map
FILE:scripts/lib/entry.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const index_1 = require("./code/index");
const ethers_1 = require("ethers");
const EXPLORER_URLS = {
eth: "https://etherscan.io",
bsc: "https://bscscan.com",
polygon: "https://polygonscan.com",
avalanche: "https://snowtrace.io",
arbitrum: "https://arbiscan.io",
zksync: "https://explorer.zksync.io",
linea: "https://lineascan.build",
base: "https://basescan.org",
opbnb: "https://opbnbscan.com",
scroll: "https://scrollscan.com",
manta_pacific: "https://manta.socialscan.net",
optimism: "https://optimistic.etherscan.io",
mantle: "https://mantlescan.xyz",
zkfair: "https://zkfair.io",
blast: "https://blastscan.io",
merlin: "https://merlinchain.io",
mode: "https://explorer.mode.network",
cyber: "https://cyber.socialscan.net",
bob: "https://bobscan.com",
lightlink: "https://explorer.lightlink.io",
nanon: "https://nanonscan.io",
bera: "https://berascan.com",
zeta: "https://zetachain-node.blockscout.com",
nibiru: "https://nibiscan.io",
abstract: "https://abscan.org",
monad: "https://monadscan.xyz",
bitlayer: "https://bitlayerscan.com",
mantra: "https://mantrascan.io",
};
// ============== Utilities ==============
function log(data) {
console.log(JSON.stringify(data));
}
function isBlank(value) {
return value == null || (typeof value === "string" && value.trim() === "");
}
function getExplorerUrl(network) {
return EXPLORER_URLS[network.toLowerCase()] || "https://etherscan.io";
}
function normalizeQuantity(quantity) {
const parsed = Number(quantity);
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
}
function calculateOrderCost(order, quantity) {
const orderPrice = Number(order?.price);
if (!Number.isFinite(orderPrice)) {
return String(order?.price ?? "");
}
const requestedQuantity = normalizeQuantity(quantity);
const availableQuantity = Number(order?.quantity);
if (String(order?.schema).toUpperCase() === "ERC1155" &&
Number.isFinite(availableQuantity) &&
availableQuantity > 0) {
return String((orderPrice * requestedQuantity) / availableQuantity);
}
return String(orderPrice * requestedQuantity);
}
function formatUnixTimestamp(timestamp) {
if (timestamp == null || timestamp === "")
return null;
const numeric = Number(timestamp);
if (!Number.isFinite(numeric) || numeric <= 0) {
return String(timestamp);
}
return new Date(numeric * 1000).toISOString().replace(".000Z", " UTC");
}
function serializeOrder(order) {
return {
orderId: order.orderId,
maker: order.maker,
contractAddress: order.contractAddress,
tokenId: order.tokenId,
schema: order.schema,
standard: order.standard,
quantity: order.quantity,
price: order.price,
priceBase: order.priceBase,
priceUSD: order.priceUSD,
paymentToken: order.paymentToken,
saleKind: order.saleKind,
side: order.side,
listingTime: formatUnixTimestamp(order.listingTime),
expirationTime: formatUnixTimestamp(order.expirationTime),
taker: order.taker,
exchangeData: order.exchangeData,
};
}
function isNativePaymentToken(paymentToken) {
if (isBlank(paymentToken))
return true;
const normalized = String(paymentToken).toLowerCase();
return normalized === index_1.NULL_ADDRESS || normalized === index_1.ETH_TOKEN_ADDRESS;
}
function extractErrorMessage(error) {
if (error?.reason)
return String(error.reason);
if (error?.message)
return String(error.message);
if (error?.error?.message)
return String(error.error.message);
if (typeof error === "string")
return error;
return JSON.stringify(error);
}
function extractErrorCode(error) {
if (error?.code)
return String(error.code);
if (error?.error?.code)
return String(error.error.code);
return null;
}
function logError(type, message, code = null, extra = {}) {
log({ status: "error", type, message, code, ...extra });
process.exit(1);
}
function validateRequiredFields(operation, values) {
const missing = values
.filter(({ value, rule }) => (rule ? !rule(value) : isBlank(value)))
.map(({ field, detail }) => ({ field, detail }));
if (missing.length === 0)
return;
const fields = missing.map((item) => item.field);
const details = missing
.filter((item) => item.detail)
.map((item) => `item.field: item.detail`);
logError("validation", `Missing or invalid required parameters for operation: fields.join(", ")`, null, {
operation,
fields,
details: details.length ? details : undefined,
});
}
function validateOrderFields(operation, order, prefix, fields) {
validateRequiredFields(operation, fields.map(({ field, detail }) => ({
field: `prefix.field`,
value: order?.[field],
detail,
})));
}
function validateInput(input) {
const { operationType } = input;
const stateChangingOperations = [
"erc721sell",
"erc1155sell",
"buy",
"offer",
"acceptOffer",
"cancel",
];
if (isBlank(operationType)) {
logError("validation", "operationType is required");
}
if (isBlank(input.network)) {
logError("validation", `network is required for operationType`, null, {
operation: operationType,
fields: ["network"],
});
}
if (stateChangingOperations.includes(operationType) &&
input.confirmed !== true) {
logError("validation", `operationType requires confirmed=true after explicit user confirmation`, null, {
operation: operationType,
fields: ["confirmed"],
});
}
switch (operationType) {
case "erc721sell": {
validateRequiredFields(operationType, [
{
field: "sellOrders.items",
value: input.sellOrders?.items,
rule: (value) => Array.isArray(value) && value.length > 0,
detail: "Provide at least one ERC721 item to list",
},
]);
(input.sellOrders?.items ?? []).forEach((item, index) => {
validateRequiredFields(operationType, [
{
field: `sellOrders.items[index].erc721TokenAddress`,
value: item?.erc721TokenAddress,
},
{
field: `sellOrders.items[index].erc721TokenId`,
value: item?.erc721TokenId,
},
{
field: `sellOrders.items[index].paymentTokenAmount`,
value: item?.paymentTokenAmount,
},
]);
});
return;
}
case "erc1155sell":
validateRequiredFields(operationType, [
{
field: "erc1155sellOrder.assetAddress",
value: input.erc1155sellOrder?.assetAddress,
},
{
field: "erc1155sellOrder.assetId",
value: input.erc1155sellOrder?.assetId,
},
{
field: "erc1155sellOrder.quantity",
value: input.erc1155sellOrder?.quantity,
},
{
field: "erc1155sellOrder.paymentTokenAmount",
value: input.erc1155sellOrder?.paymentTokenAmount,
},
]);
return;
case "offer":
validateRequiredFields(operationType, [
{
field: "offerOrder.assetAddress",
value: input.offerOrder?.assetAddress,
},
{
field: "offerOrder.assetSchema",
value: input.offerOrder?.assetSchema,
detail: "Explicitly set ERC721 or ERC1155 for offer creation",
},
{
field: "offerOrder.paymentTokenAmount",
value: input.offerOrder?.paymentTokenAmount,
},
]);
return;
case "acceptOffer": {
validateRequiredFields(operationType, [
{
field: "acceptOfferOrder.order",
value: input.acceptOfferOrder?.order,
},
]);
const order = input.acceptOfferOrder?.order;
validateOrderFields(operationType, order, "acceptOfferOrder.order", [
{ field: "orderId" },
{ field: "contractAddress" },
{ field: "standard" },
{ field: "schema" },
{ field: "side", detail: "Use a buy-side order returned by query" },
{ field: "paymentToken" },
{ field: "price" },
]);
const saleKind = Number(order?.saleKind);
if ((saleKind === 7 || saleKind === 8) &&
isBlank(input.acceptOfferOrder?.assetId)) {
logError("validation", "acceptOfferOrder.assetId is required for collection-wide offers", null, { operation: operationType, fields: ["acceptOfferOrder.assetId"] });
}
return;
}
case "buy": {
validateRequiredFields(operationType, [
{
field: "buyOrders.orders",
value: input.buyOrders?.orders,
rule: (value) => Array.isArray(value) && value.length > 0,
detail: "Provide at least one order returned by query",
},
]);
const orders = input.buyOrders?.orders ?? [];
orders.forEach((order, index) => {
validateOrderFields(operationType, order, `buyOrders.orders[index]`, [
{ field: "orderId" },
{ field: "contractAddress" },
{ field: "standard" },
{ field: "schema" },
{
field: "side",
detail: "Use a sell-side order returned by query",
},
{ field: "paymentToken" },
{ field: "price" },
]);
if (!isNativePaymentToken(order?.paymentToken)) {
validateRequiredFields(operationType, [
{
field: `buyOrders.orders[index].paymentTokenDecimals`,
value: order?.paymentTokenDecimals,
detail: "ERC20-priced buys require paymentTokenDecimals; look it up from the payment token reference instead of guessing",
},
]);
}
});
const hasERC1155 = orders.some((order) => String(order?.schema).toUpperCase() === "ERC1155");
if (hasERC1155) {
validateRequiredFields(operationType, [
{
field: "buyOrders.quantities",
value: input.buyOrders?.quantities,
rule: (value) => Array.isArray(value) && value.length === orders.length,
detail: "ERC1155 buys require a quantities array aligned with orders",
},
]);
}
return;
}
case "query":
validateRequiredFields(operationType, [
{
field: "queryOrders.asset_contract_address",
value: input.queryOrders?.asset_contract_address,
},
]);
return;
case "queryAccountOrders":
return;
case "cancel": {
validateRequiredFields(operationType, [
{
field: "ordersToCancel.orders",
value: input.ordersToCancel?.orders,
rule: (value) => Array.isArray(value) && value.length > 0,
detail: "Provide at least one full order object to cancel",
},
]);
(input.ordersToCancel?.orders ?? []).forEach((order, index) => {
validateOrderFields(operationType, order, `ordersToCancel.orders[index]`, [
{ field: "maker" },
{ field: "schema" },
{ field: "standard" },
{ field: "exchangeData" },
]);
});
return;
}
case "getAddress":
return;
default:
return;
}
}
// ============== Credentials & SDK ==============
async function getCredentials() {
const apiKeyFromEnv = process.env.ELEMENT_API_KEY;
const privateKeyFromEnv = process.env.ELEMENT_WALLET_PRIVATE_KEY;
if (!apiKeyFromEnv || !privateKeyFromEnv) {
throw new Error("Missing required environment variables: ELEMENT_API_KEY and ELEMENT_WALLET_PRIVATE_KEY");
}
return {
apiKey: apiKeyFromEnv,
wallet: { private_key: privateKeyFromEnv },
};
}
async function createSDK(network) {
const credentials = await getCredentials();
const chainId = (0, index_1.getChainId)(network, false);
const chainMId = (0, index_1.getChainMId)(chainId);
const rpcUrl = await (0, index_1.getRpcUrlFromRemote)(chainMId);
const provider = new ethers_1.ethers.providers.JsonRpcProvider(rpcUrl);
const signer = new ethers_1.ethers.Wallet(credentials.wallet.private_key, provider);
return new index_1.ElementSDK({
networkName: network,
isTestnet: false,
apiKey: credentials.apiKey,
signer: signer,
});
}
async function getInput() {
if (process.argv[2]) {
try {
return JSON.parse(process.argv[2]);
}
catch (e) {
throw new Error(`Invalid JSON in command argument: extractErrorMessage(e)`);
}
}
return new Promise((resolve, reject) => {
let data = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
data += chunk;
});
process.stdin.on("end", () => {
try {
resolve(JSON.parse(data.trim()));
}
catch (e) {
reject(new Error(`Invalid JSON in stdin: extractErrorMessage(e)`));
}
});
process.stdin.on("error", (e) => reject(new Error(`stdin error: extractErrorMessage(e)`)));
});
}
// ============== Operation Handlers ==============
async function handleERC721Sell(sdk, params) {
if (!params)
throw new Error("sellOrders is not set");
const result = await sdk.makeERC721SellOrders(params);
if (result.succeedList.length === 0 && result.failedList.length > 0) {
logError("erc721sell", "All orders failed", null, {
failedList: result.failedList.map((item) => ({
tokenId: item.assetTokenId,
contractAddress: item.assetContract,
error: item.errorDetail,
})),
});
}
log({
status: "success",
operation: "erc721sell",
succeedCount: result.succeedList.length,
failedCount: result.failedList.length,
succeedList: result.succeedList.map((o) => ({
orderId: o.orderId,
contractAddress: o.contractAddress,
tokenId: o.tokenId,
price: o.price,
paymentToken: o.paymentToken,
expirationTime: formatUnixTimestamp(o.expirationTime),
})),
failedList: result.failedList.map((item) => ({
tokenId: item.assetTokenId,
contractAddress: item.assetContract,
error: item.errorDetail,
})),
});
}
async function handleERC1155Sell(sdk, params) {
if (!params)
throw new Error("erc1155sellOrder is not set");
const result = await sdk.makeSellOrder(params);
log({
status: "success",
operation: "erc1155sell",
orderId: result.orderId,
contractAddress: result.contractAddress,
tokenId: result.tokenId,
price: result.price,
paymentToken: result.paymentToken,
listingTime: formatUnixTimestamp(result.listingTime),
expirationTime: formatUnixTimestamp(result.expirationTime),
});
}
async function handleBuy(sdk, params, explorerBase) {
if (!params)
throw new Error("buyOrders is not set");
const orders = params.orders ?? [];
const hasERC20Payment = orders.some((order) => !isNativePaymentToken(order?.paymentToken));
if (hasERC20Payment) {
if (orders.length !== 1) {
logError("buy", "ERC20-priced buys currently support exactly one order at a time", null, {
orderCount: orders.length,
paymentTokens: orders.map((order) => order?.paymentToken ?? null),
});
}
const order = orders[0];
const quantity = params.quantities?.[0];
const tx = await sdk.fillOrder({
order,
quantity,
});
let receipt;
try {
receipt = await tx.wait();
}
catch (e) {
logError("buy", `Transaction failed on-chain: extractErrorMessage(e)`, extractErrorCode(e), {
transactionHash: tx.hash,
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
log({
status: receipt.status === 1 ? "success" : "failed",
operation: "buy",
paymentMode: "erc20-single-fill",
orders: [
{
orderId: order.orderId,
contractAddress: order.contractAddress,
tokenId: order.tokenId,
schema: order.schema,
requestedQuantity: String(quantity ?? "1"),
paymentToken: order.paymentToken,
cost: calculateOrderCost(order, quantity),
},
],
transactionHash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
explorerUrl: `explorerBase/tx/tx.hash`,
});
return;
}
const tx = await sdk.batchBuyWithETH(params);
let receipt;
try {
receipt = await tx.wait();
}
catch (e) {
logError("buy", `Transaction failed on-chain: extractErrorMessage(e)`, extractErrorCode(e), {
transactionHash: tx.hash,
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
log({
status: receipt.status === 1 ? "success" : "failed",
operation: "buy",
paymentMode: "native-batch-buy",
orders: params.orders.map((order, index) => ({
orderId: order.orderId,
contractAddress: order.contractAddress,
tokenId: order.tokenId,
schema: order.schema,
requestedQuantity: String(params.quantities?.[index] ?? "1"),
paymentToken: order.paymentToken,
cost: calculateOrderCost(order, params.quantities?.[index]),
})),
transactionHash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
async function handleOffer(sdk, params) {
if (!params)
throw new Error("offerOrder is not set");
const result = await sdk.makeBuyOrder(params);
log({
status: "success",
operation: "offer",
orderId: result.orderId,
contractAddress: result.contractAddress,
price: result.price,
paymentToken: result.paymentToken,
listingTime: formatUnixTimestamp(result.listingTime),
expirationTime: formatUnixTimestamp(result.expirationTime),
});
}
async function handleAcceptOffer(sdk, params, explorerBase) {
if (!params?.order)
throw new Error("acceptOfferOrder.order is not set");
const tx = await sdk.fillOrder(params);
let receipt;
try {
receipt = await tx.wait();
}
catch (e) {
logError("acceptOffer", `Transaction failed on-chain: extractErrorMessage(e)`, extractErrorCode(e), {
transactionHash: tx.hash,
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
log({
status: receipt.status === 1 ? "success" : "failed",
operation: "acceptOffer",
acceptedOffer: {
orderId: params.order.orderId,
maker: params.order.maker,
contractAddress: params.order.contractAddress,
tokenId: String(params.assetId ?? params.order.tokenId ?? ""),
schema: params.order.schema,
quantity: String(params.quantity ?? "1"),
paymentToken: params.order.paymentToken,
price: params.order.price,
proceeds: calculateOrderCost(params.order, params.quantity),
},
transactionHash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
explorerUrl: `explorerBase/tx/tx.hash`,
});
}
async function handleQuery(sdk, query) {
if (!query?.asset_contract_address) {
throw new Error("asset_contract_address is not set");
}
const orders = await sdk.queryOrders(query);
log({
status: "success",
operation: "query",
count: orders.length,
orders: orders.map((o) => serializeOrder(o)),
});
}
async function handleQueryAccountOrders(sdk, params = {}) {
const payload = await sdk.queryAccountOrders(params);
const assetList = payload?.assetList ?? [];
const chain = (sdk.apiOption?.chain || "").toString();
log({
status: "success",
operation: "queryAccountOrders",
chain,
usingDefaultAccount: isBlank(params.wallet_address),
walletAddress: params.wallet_address ?? null,
contractAddress: params.contract_address ?? null,
cursor: params.cursor ?? null,
pageInfo: payload?.pageInfo ?? null,
count: assetList.length,
orders: assetList.map((item) => ({
cursor: item?.cursor ?? null,
name: item?.asset?.name,
slug: item?.asset?.collection?.slug,
tokenId: item?.asset?.tokenId,
collection: item?.asset?.collection?.name,
contractAddress: item?.asset?.contractAddress,
price: item?.orderData?.accountOrder?.price,
priceUSD: item?.orderData?.accountOrder?.priceUSD,
paymentToken: item?.orderData?.accountOrder?.paymentToken,
quantity: item?.orderData?.accountOrder?.quantity,
side: item?.orderData?.accountOrder?.side,
saleKind: item?.orderData?.accountOrder?.saleKind,
standard: item?.orderData?.accountOrder?.standard,
schema: item?.orderData?.accountOrder?.schema,
listingTime: formatUnixTimestamp(item?.orderData?.accountOrder?.listingTime),
expirationTime: formatUnixTimestamp(item?.orderData?.accountOrder?.expirationTime),
})),
});
}
async function handleGetAddress(sdk) {
const address = await sdk.web3Signer.getCurrentAccount();
log({
status: "success",
operation: "getAddress",
address,
});
}
async function handleCancel(sdk, params, explorerBase) {
if (!params?.orders?.length)
throw new Error("ordersToCancel is not set or empty");
const result = await sdk.cancelOrders({ orders: params.orders });
if (result.succeedTransactions.length === 0) {
logError("cancel", "No orders were successfully cancelled");
}
const transactions = [];
for (const txInfo of result.succeedTransactions) {
let receipt;
try {
receipt = await txInfo.transaction.wait();
}
catch (e) {
transactions.push({
transactionHash: txInfo.transaction.hash,
status: "failed",
message: extractErrorMessage(e),
explorerUrl: `explorerBase/tx/txInfo.transaction.hash`,
});
continue;
}
transactions.push({
transactionHash: txInfo.transaction.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
status: receipt.status === 1 ? "success" : "failed",
explorerUrl: `explorerBase/tx/txInfo.transaction.hash`,
});
}
log({
status: "success",
operation: "cancel",
cancelledCount: result.succeedTransactions.length,
transactions,
});
}
// ============== Main ==============
async function main() {
let input;
try {
input = await getInput();
}
catch (e) {
logError("input", extractErrorMessage(e), extractErrorCode(e));
}
validateInput(input);
const { network, operationType } = input;
let sdk;
const needsSdk = true;
if (needsSdk) {
try {
sdk = await createSDK(network);
}
catch (e) {
logError("sdk_init", extractErrorMessage(e), extractErrorCode(e));
}
}
const explorerBase = network
? getExplorerUrl(network)
: "https://etherscan.io";
try {
switch (operationType) {
case "erc721sell":
await handleERC721Sell(sdk, input.sellOrders);
break;
case "erc1155sell":
await handleERC1155Sell(sdk, input.erc1155sellOrder);
break;
case "buy":
await handleBuy(sdk, input.buyOrders, explorerBase);
break;
case "offer":
await handleOffer(sdk, input.offerOrder);
break;
case "acceptOffer":
await handleAcceptOffer(sdk, input.acceptOfferOrder, explorerBase);
break;
case "query":
await handleQuery(sdk, input.queryOrders);
break;
case "queryAccountOrders":
await handleQueryAccountOrders(sdk, input.queryAccountOrders);
break;
case "cancel":
await handleCancel(sdk, input.ordersToCancel, explorerBase);
break;
case "getAddress":
await handleGetAddress(sdk);
break;
default:
throw new Error(`Unsupported operation type: operationType`);
}
}
catch (e) {
logError(operationType || "unknown", extractErrorMessage(e), extractErrorCode(e));
}
}
main();
//# sourceMappingURL=entry.js.map
FILE:scripts/tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": [
"ES2020"
],
"outDir": "./lib",
"rootDir": ".",
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": [
"entry.ts",
"code/**/*"
],
"exclude": [
"node_modules",
"lib",
"dist"
]
}