├── .changeset ├── README.md └── config.json ├── .env.example ├── .github ├── dependabot.yml └── workflows │ ├── changesets.yml │ ├── deploy-docs.yml │ ├── project.yml │ ├── pull-request.yml │ └── verify.yml ├── .gitignore ├── .npmignore ├── CONTRIBUTING.MD ├── LICENSE ├── README.md ├── biome.json ├── bun.lockb ├── docs ├── .gitignore ├── README.md ├── bun.lockb ├── package.json ├── pages │ ├── docs │ │ ├── authentication.mdx │ │ ├── collecting-data │ │ │ ├── adding-tasks.mdx │ │ │ ├── collecting-results.mdx │ │ │ ├── create-a-campaign.mdx │ │ │ ├── create-a-template.mdx │ │ │ └── introduction.mdx │ │ ├── compatibility.mdx │ │ ├── faq.mdx │ │ ├── getting-started.mdx │ │ ├── glossary │ │ │ ├── terminology.mdx │ │ │ └── types.mdx │ │ ├── introduction.mdx │ │ ├── local-development.mdx │ │ ├── tasks │ │ │ ├── batches │ │ │ │ ├── create-batch.mdx │ │ │ │ └── get-batch.mdx │ │ │ ├── campaigns │ │ │ │ ├── create-campaign.mdx │ │ │ │ ├── get-all-campaigns.mdx │ │ │ │ ├── get-campaign-by-id.mdx │ │ │ │ └── get-campaigns.mdx │ │ │ ├── get-acc-task-idx.mdx │ │ │ ├── get-repetions.mdx │ │ │ ├── get-submissions.mdx │ │ │ ├── get-task.mdx │ │ │ ├── reservations │ │ │ │ ├── get-reservations.mdx │ │ │ │ └── reserve-task.mdx │ │ │ └── submit-task.mdx │ │ ├── templates │ │ │ ├── introduction.mdx │ │ │ ├── labelstudio.mdx │ │ │ └── placeholders.mdx │ │ ├── token │ │ │ ├── get-balance.mdx │ │ │ ├── get-price.mdx │ │ │ ├── swap.mdx │ │ │ └── transfer.mdx │ │ └── vaccount │ │ │ ├── claim.mdx │ │ │ ├── create-account.mdx │ │ │ ├── deposit.mdx │ │ │ ├── get-accounts.mdx │ │ │ ├── get-avatar.mdx │ │ │ ├── get-or-create.mdx │ │ │ ├── get-pending-payments.mdx │ │ │ ├── payout.mdx │ │ │ ├── transfer.mdx │ │ │ └── withdraw.mdx │ └── index.mdx ├── public │ ├── .nojekyll │ ├── CNAME │ ├── colosseum-light.svg │ ├── effect-logo-black.png │ ├── effect_template_placeholder_example.png │ ├── labelstudioocr.png │ ├── logo.png │ └── preview-bg.png ├── sidebar.ts ├── snippets │ ├── getting-started │ │ ├── getting-started-auth.ts │ │ ├── getting-started-init.ts │ │ └── getting-started-nonauth.ts │ ├── tasks │ │ ├── create-campaign.ts │ │ ├── get-campaign-by-id.ts │ │ └── get-campaigns.ts │ ├── templates │ │ ├── example.json │ │ ├── index.html │ │ ├── input_schema.json │ │ └── script.ts │ ├── token │ │ ├── get-balance.ts │ │ ├── get-price.ts │ │ ├── swap.ts │ │ └── transfer.ts │ └── vaccount │ │ ├── claim.ts │ │ ├── create-account.ts │ │ ├── deposit.ts │ │ ├── get-accounts.ts │ │ ├── get-pending-payments.ts │ │ ├── payout.ts │ │ └── withdraw.ts ├── styles.css ├── tailwind.config.cjs └── vocs.config.tsx ├── environments ├── node │ ├── .gitignore │ ├── README.md │ ├── bun.lockb │ ├── index.ts │ ├── package.json │ └── tsconfig.json └── vite │ ├── .gitignore │ ├── README.md │ ├── bun.lockb │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── examples └── README.md ├── package.json ├── scripts ├── generateAbiTypes.ts └── updateVersion.ts ├── src ├── @generated │ ├── structs │ │ └── effecttasks2.ts │ └── types │ │ ├── tasks.efx.ts │ │ └── vaccount.efx.ts ├── CHANGELOG.md ├── LICENSE ├── README.md ├── actions │ ├── atomic │ │ ├── getAccountAssets.test.ts │ │ ├── getAccountAssets.ts │ │ ├── getAsset.ts │ │ ├── getCollection.ts │ │ └── getSchema.ts │ ├── dao │ │ ├── getAvatar.ts │ │ ├── getDaoSettings.ts │ │ └── setAvatar.ts │ ├── ipfs │ │ ├── getIpfsResource.ts │ │ └── uploadIpfsResource.ts │ ├── session │ │ ├── createSession.ts │ │ └── setSession.ts │ ├── tasks │ │ ├── batch │ │ │ ├── createBatch.test.ts │ │ │ ├── createBatch.ts │ │ │ ├── getBatch.test.ts │ │ │ └── getBatch.ts │ │ ├── campaigns │ │ │ ├── createCampaign.test.ts │ │ │ ├── createCampaign.ts │ │ │ ├── getAllCampaigns.test.ts │ │ │ ├── getAllCampaigns.ts │ │ │ ├── getCampaignById.test.ts │ │ │ ├── getCampaignById.ts │ │ │ ├── getCampaigns.test.ts │ │ │ └── getCampaigns.ts │ │ ├── getAccTaskIdx.test.ts │ │ ├── getAccTaskIdx.ts │ │ ├── getForceSettings.test.ts │ │ ├── getForceSettings.ts │ │ ├── getRepetitions.test.ts │ │ ├── getRepetitions.ts │ │ ├── getSubmissions.test.ts │ │ ├── getSubmissions.ts │ │ ├── getTask.test.ts │ │ ├── getTask.ts │ │ ├── reservations │ │ │ ├── getReservations.test.ts │ │ │ ├── getReservations.ts │ │ │ ├── reserveTask.test.ts │ │ │ └── reserveTask.ts │ │ ├── submitTask.test.ts │ │ └── submitTask.ts │ ├── token │ │ ├── getBalance.test.ts │ │ ├── getBalance.ts │ │ ├── getDefiBoxPair.test.ts │ │ ├── getDefiBoxPair.ts │ │ ├── getPrice.test.ts │ │ ├── getPrice.ts │ │ ├── swap.test.ts │ │ └── swap.ts │ └── vaccount │ │ ├── claim.test.ts │ │ ├── claim.ts │ │ ├── createAccount.test.ts │ │ ├── createAccount.ts │ │ ├── deposit.test.ts │ │ ├── deposit.ts │ │ ├── getAccounts.test.ts │ │ ├── getAccounts.ts │ │ ├── getAvatar.test.ts │ │ ├── getAvatar.ts │ │ ├── getOrCreate.test.ts │ │ ├── getOrCreate.ts │ │ ├── getPendingPayments.test.ts │ │ ├── getPendingPayments.ts │ │ ├── payout.test.ts │ │ ├── payout.ts │ │ ├── transfer.test.ts │ │ ├── transfer.ts │ │ ├── withdraw.test.ts │ │ └── withdraw.ts ├── cache.ts ├── client.test.ts ├── client.ts ├── constants │ ├── config.ts │ └── network.ts ├── errors.ts ├── exports │ ├── constants.ts │ ├── errors.ts │ ├── index.ts │ ├── template.ts │ ├── types.ts │ └── version.ts ├── jsconfig.json ├── package.json ├── session.ts ├── template │ ├── template.ts │ └── templateScript.ts ├── tsconfig.build.json ├── types │ ├── helpers.ts │ ├── network.ts │ └── user.ts └── utils │ ├── keys.ts │ ├── state.ts │ ├── structs.ts │ ├── transaction.ts │ └── variants.ts ├── test └── src │ ├── constants.ts │ └── utils.ts └── tsconfig.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | PERMISSION=active 2 | NETWORK_NAME=mainnet 3 | ACTOR=eosaccountname 4 | PRIVATE_KEY=private_key_here 5 | PUBLIC_KEY=public_key_here 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | open-pull-requests-limit: 0 8 | 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "monthly" 13 | -------------------------------------------------------------------------------- /.github/workflows/changesets.yml: -------------------------------------------------------------------------------- 1 | name: Changesets 2 | on: 3 | push: 4 | branches: [main, rc] 5 | workflow_dispatch: 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | verify: 13 | name: Verify 14 | uses: ./.github/workflows/verify.yml 15 | secrets: inherit 16 | 17 | changesets: 18 | name: Create version pull request 19 | runs-on: ubuntu-latest 20 | timeout-minutes: 5 21 | 22 | steps: 23 | - name: Clone repository 24 | uses: actions/checkout@v4 25 | with: 26 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 27 | fetch-depth: 0 28 | 29 | - uses: oven-sh/setup-bun@v1 30 | 31 | - name: Install dependencies 32 | run: bun install --frozen-lockfile 33 | 34 | - name: Create Version Pull Request 35 | uses: changesets/action@v1 36 | with: 37 | commit: "chore: version package" 38 | title: "chore: version package" 39 | version: bun changeset:version 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | 43 | release: 44 | name: Release 45 | needs: verify 46 | runs-on: ubuntu-latest 47 | timeout-minutes: 5 48 | permissions: 49 | contents: write 50 | id-token: write 51 | 52 | steps: 53 | - name: Clone repository 54 | uses: actions/checkout@v4 55 | 56 | - uses: oven-sh/setup-bun@v1 57 | 58 | - name: Install dependencies 59 | run: bun install --frozen-lockfile 60 | 61 | - name: Publish to NPM 62 | uses: changesets/action@v1 63 | with: 64 | createGithubReleases: ${{ github.ref == 'refs/heads/main' }} 65 | publish: bun changeset:publish 66 | env: 67 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 68 | NPM_TOKEN: ${{ secrets.NPMJS_TOKEN }} 69 | # https://docs.npmjs.com/generating-provenance-statements 70 | NPM_CONFIG_PROVENANCE: true 71 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on gh-pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Setup Bun 15 | uses: oven-sh/setup-bun@v1 16 | 17 | - name: Set up Node 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 21 21 | 22 | - run: bun install --frozen-lockfile 23 | 24 | - run: bun run build 25 | 26 | - name: deploy 27 | uses: peaceiris/actions-gh-pages@v4 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | publish_dir: ./docs/dist 31 | -------------------------------------------------------------------------------- /.github/workflows/project.yml: -------------------------------------------------------------------------------- 1 | name: Add bounty to Bounty Board 2 | 3 | on: 4 | issues: 5 | types: 6 | - labeled 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v0.4.0 14 | with: 15 | project-url: https://github.com/orgs/effectai/projects/6 # bounty board project 16 | github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} 17 | labeled: bounty 18 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Pull request 2 | on: 3 | pull_request: 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | verify: 11 | name: Verify 12 | uses: ./.github/workflows/verify.yml 13 | secrets: inherit 14 | 15 | # size: 16 | # name: Size 17 | # runs-on: ubuntu-latest 18 | # timeout-minutes: 5 19 | 20 | # steps: 21 | # - name: Clone repository 22 | # uses: actions/checkout@v4 23 | 24 | # - name: Setup Bun 25 | # uses: oven-sh/setup-bun@v1 26 | 27 | # - name: Install dependencies 28 | # run: bun install --frozen-lockfile 29 | 30 | # - name: Report bundle size 31 | # uses: andresz1/size-limit-action@master 32 | # with: 33 | # github_token: ${{ secrets.GITHUB_TOKEN }} 34 | # package_manager: bun 35 | -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify 2 | on: 3 | workflow_call: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | lint: 8 | name: Lint 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 5 11 | 12 | steps: 13 | - name: Clone repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Bun 17 | uses: oven-sh/setup-bun@v1 18 | 19 | - name: Install dependencies 20 | run: bun install --frozen-lockfile 21 | 22 | - name: Lint code 23 | run: bun format && bun lint 24 | 25 | - uses: stefanzweifel/git-auto-commit-action@v5 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | with: 29 | commit_message: "chore: format" 30 | commit_user_name: "github-actions[bot]" 31 | 32 | build: 33 | name: Build 34 | needs: lint 35 | runs-on: ubuntu-latest 36 | timeout-minutes: 5 37 | steps: 38 | - name: Clone repository 39 | uses: actions/checkout@v4 40 | 41 | - name: Setup Bun 42 | uses: oven-sh/setup-bun@v1 43 | 44 | - name: Install dependencies 45 | run: bun install --frozen-lockfile 46 | 47 | - name: Build 48 | run: bun run build 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | 4 | # Log files 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | .projectile 13 | 14 | # local env files 15 | .env 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | .env.testnet 21 | .env.mainnet 22 | .envrc 23 | 24 | # ignore lock files other then bun. 25 | package-lock.json 26 | yarn.lock 27 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Exclude all files by default 2 | * 3 | 4 | # Include distribution bundle but exclude test files if they are built into dist 5 | !dist/** 6 | *.test.* 7 | 8 | # Include documentation and version information in bundle 9 | !CONTRIBUTING.md 10 | 11 | # Include any additional source files which should be bundled 12 | !src/**/*.abi.json 13 | 14 | # dotenv environment file 15 | .env 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | src/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | src/README.md -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.7.0/schema.json", 3 | "organizeImports": { 4 | "enabled": true 5 | }, 6 | "formatter": { 7 | "enabled": true, 8 | "ignore": ["dist", "test"] 9 | }, 10 | "linter": { 11 | "ignore": ["dist", "test", "scripts"], 12 | "enabled": true, 13 | "rules": { 14 | "recommended": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/bun.lockb -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # site 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.3. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. 16 | -------------------------------------------------------------------------------- /docs/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/bun.lockb -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@effectai/sdkdocs", 3 | "type": "module", 4 | "private": true, 5 | "scripts": { 6 | "dev": "bun install && vocs dev", 7 | "build": "vocs build --searchIndex false && vocs search-index", 8 | "preview": "vocs preview" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@wharfkit/wallet-plugin-anchor": "^1.0.0", 13 | "@wharfkit/web-renderer": "^1.0.3", 14 | "@wharfkit/wallet-plugin-privatekey": "1.1.0", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0", 17 | "vocs": "^1.0.0-alpha.52", 18 | "@types/bun": "latest" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/pages/docs/authentication.mdx: -------------------------------------------------------------------------------- 1 | # Authentication 2 | Some functions in the Effect AI SDK require authentication with the EOS blockchain. This is done by passing a session object to the createClient function. 3 | A session can be established by either [private key](https://github.com/wharfkit/wallet-plugin-privatekey) or [wallet plugins](https://wharfkit.com/plugins?tag=wallet-plugin). 4 | 5 | ### Private Key 6 | To authenticate using a private key we recommend using the [wallet-plugin-privatekey](https://github.com/wharfkit/wallet-plugin-privatekey) 7 | And passing it through a session to the `createClient` function. 8 | 9 | ```ts twoslash 10 | import { 11 | createClient, 12 | eos, 13 | Session 14 | } from "@effectai/sdk"; 15 | 16 | import { WalletPluginPrivateKey } from '@wharfkit/wallet-plugin-privatekey' 17 | 18 | const session = new Session({ 19 | chain: eos, 20 | walletPlugin: new WalletPluginPrivateKey( 21 | '5Jtoxgny5tT7NiNFp1MLogviuPJ9NniWjnU4wKzaX4t7pL4kJ8s', 22 | ), 23 | }) 24 | 25 | const client = await createClient({ session }) 26 | ``` 27 | 28 | ### Wallet Plugin 29 | It's also possible to authenticate using a wallet plugin, for example using the [wallet-plugin-anchor](https://github.com/wharfkit/wallet-plugin-anchor) 30 | This one is a bit more complicated and requires two additional packages: [`@wharfkit/session`](https://github.com/wharfkit/session) and [`@wharfkit/web-renderer`](https://github.com/wharfkit/web-renderer) 31 | 32 | ```ts twoslash 33 | import { 34 | createClient, 35 | eos, 36 | } from "@effectai/sdk"; 37 | 38 | import { SessionKit } from "@wharfkit/session"; 39 | import { WebRenderer } from "@wharfkit/web-renderer"; 40 | import { WalletPluginAnchor } from "@wharfkit/wallet-plugin-anchor"; 41 | 42 | const webRenderer = new WebRenderer(); 43 | 44 | const sessionKit = new SessionKit( 45 | { 46 | appName: "", 47 | chains: [eos], 48 | ui: webRenderer, 49 | walletPlugins: [ 50 | new WalletPluginAnchor(), 51 | ], 52 | }, 53 | ) 54 | 55 | const session = await sessionKit.restore(); 56 | 57 | if(!session) { 58 | throw new Error('Session not found') 59 | } 60 | 61 | const client = await createClient({ session }) 62 | ``` -------------------------------------------------------------------------------- /docs/pages/docs/collecting-data/adding-tasks.mdx: -------------------------------------------------------------------------------- 1 | ## Adding tasks 2 | 3 | Adding tasks to a campaign is done through adding batches. 4 | 5 | Batches are a collection of tasks that are added to a campaign. Each batch can contain multiple tasks. 6 | Let's start by creating a batch with 3 tasks to our newly created image classification campaign. 7 | 8 | ```ts twoslash 9 | // [!include ~/snippets/getting-started/getting-started-auth.ts] 10 | if(!client.session) { 11 | throw new Error('No session found') 12 | } 13 | const { actor } = client.session 14 | 15 | if(!actor) { 16 | throw new Error('No actor found') 17 | } 18 | //---cut--- 19 | import { createBatch } from '@effectai/sdk' 20 | 21 | const batch = await createBatch({ 22 | client, 23 | // The campaign id to which the batch should be added 24 | campaignId : 1, 25 | // The number of times each task in the batch should be repeated 26 | repetitions: 1, 27 | // The reward for each task in the batch 28 | reward: 3, 29 | // The template placeholders for each task in the batch 30 | taskData : [ 31 | { 32 | ipfs_url: 'https://example.com/image.jpg', //task 1 image placeholder 33 | }, 34 | { 35 | ipfs_url: 'https://example.com/image2.jpg', //task 2 image placeholder 36 | }, 37 | { 38 | ipfs_url: 'https://example.com/image3.jpg', // task 3 image placeholder 39 | } 40 | ], 41 | }) 42 | 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /docs/pages/docs/collecting-data/collecting-results.mdx: -------------------------------------------------------------------------------- 1 | ## Collecting Results 2 | 3 | TODO:: -------------------------------------------------------------------------------- /docs/pages/docs/collecting-data/create-a-campaign.mdx: -------------------------------------------------------------------------------- 1 | ## Creating Your First Campaign 2 | 3 | Campaigns are the main way to collect data on Effect Network. 4 | A campaign is a collection of tasks that need to be completed by workers. Each task is a small piece of work that needs to be done. For example, a task could be to label an image, transcribe a piece of audio, or answer a question. 5 | They are created by the data requester (you) and contain information like the reward for the workers, the template for the tasks, the instructions for the workers etc. 6 | 7 | ### Creating a campaign 8 | 9 | ```ts twoslash 10 | // [!include ~/snippets/tasks/create-campaign.ts] 11 | 12 | ``` 13 | 14 | Wooooho! You have created your first campaign. You can now view the campaign on the [Effect Network](https://app.effect.network/campaigns) before you start collecting data, you need to add tasks to the campaign. You can do this by following the [Adding Tasks](/docs/collecting-data/adding-tasks) guide. 15 | -------------------------------------------------------------------------------- /docs/pages/docs/collecting-data/create-a-template.mdx: -------------------------------------------------------------------------------- 1 | 2 | # Create a Template 3 | Before we can create a data collection campaign, we need to create a **template**. 4 | 5 | A template is a blueprint for the tasks in a campaign. It defines the structure of the tasks, the input and output data. 6 | Templates are created by the data requester (you) and can be reused across multiple campaigns. 7 | 8 | A typical template will be a HTML file that contains the structure of the tasks. The template can contain placeholders for the input data, output data, and other dynamic content. 9 | In this case, we aim to determine whether an image depicts a Chihuahua or a muffin. 10 | Our template should include the following: 11 | 12 | - **Load an Image**: In order for our workers to distinguish between a Chihuahua or a Muffin, an image must be loaded and displayed to them. 13 | - **HTML Form**: We must integrate an HTML form into the template so our users can fill in whether the loaded image is a Chihuahua or a Muffin. 14 | 15 | ```html 16 | 17 | 18 | Chihuahua or Muffin 19 | 20 | 21 |
22 |
23 |

Chihuahua or Muffin ?

24 | 25 | 26 |
27 |
28 | 29 |

Is this an image of a Chihuahua or a Muffin?

30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 |
43 | 44 | 45 | ``` 46 | 47 | In the above template, we are making use of a placeholder `${ipfs_url}` 48 | This value will be filled with our images when we create the tasks. 49 | 50 | You can find examples for different types of templates on our [github](https://github.com/effectai/effect-force-templates) 51 | We highly recommended to follow the [template guide](/docs/templates/introduction) when you are creating your own template. 52 | 53 | 54 | Now that we have created a template for our campaign, we can move on to the next step: [Creating a Campaign](/docs/collecting-data/create-a-campaign) -------------------------------------------------------------------------------- /docs/pages/docs/collecting-data/introduction.mdx: -------------------------------------------------------------------------------- 1 | # Data Collection 2 | The primary use case of the Effect Network SDK revolves around leveraging its capabilities for data collection. In this section, we'll guide you through setting up your first data collection campaign. 3 | Whether you're building AI models, conducting surveys, or enhancing automated processes, 4 | the Effect Network offers a robust infrastructure to support your needs in a completely open, decentralized an transparent way. 5 | 6 | ## Image annotation for AI training 7 | 8 | For this tutorial, let's dive into a practical example: utilizing the Effect AI Network to annotate images distinguishing between a **chihuahua** and a **muffin**. 9 | This annotated data will serve as training material for our AI model. 10 | It's important to note that this is just one of many potential applications. Other examples include: 11 | 12 | - Gathering survey data from a specific target audience 13 | - Employing the Effect AI Network for final quality checks in a Language Model (LLM) pipeline for automated transcriptions 14 | - Playing chess against a random human 15 | - Many more! 16 | 17 | Please check out our [example folder](https://github.com/effectai/effect-js/tree/dev/examples) on github if you want to check out other examples or want to contribute! -------------------------------------------------------------------------------- /docs/pages/docs/compatibility.mdx: -------------------------------------------------------------------------------- 1 | # Compatibility 2 | 3 | The Effect AI SDK is compatible with all Node.js environments, including browsers and React Native. 4 | It might be necessary to use a particular `fetch` polyfill in some environments. 5 | -------------------------------------------------------------------------------- /docs/pages/docs/faq.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/faq.mdx -------------------------------------------------------------------------------- /docs/pages/docs/getting-started.mdx: -------------------------------------------------------------------------------- 1 | # Getting Started [Get started with the SDK in just a few lines of code.] 2 | 3 | ## Installation 4 | 5 | Use your favorite package manager to install the SDK. 6 | The sdk is available on [npm](https://www.npmjs.com/package/@effectai/sdk) 7 | 8 | :::code-group 9 | 10 | ```bash [npm] 11 | npm i @effectai/sdk 12 | ``` 13 | 14 | ```bash [bun] 15 | bun i @effectai/sdk 16 | ``` 17 | 18 | ```bash [pnpm] 19 | pnpm i @effectai/sdk 20 | ``` 21 | ::: 22 | 23 | ## Quick Start 24 | 25 | ### 1. Import and Instantiate the EffectAI Client 26 | 27 | :::code-group 28 | 29 | ```ts twoslash [EOS Testnet] 30 | import { 31 | createClient, 32 | jungle4 33 | } from "@effectai/sdk"; 34 | 35 | const client = await createClient({ network: jungle4 }); 36 | ``` 37 | 38 | ```ts twoslash [EOS Mainnet] 39 | import { 40 | createClient, 41 | eos 42 | } from "@effectai/sdk"; 43 | 44 | const client = await createClient({ network: eos }); 45 | ``` 46 | 47 | ::: 48 | 49 | ### 2. Using the client 50 | ```ts twoslash 51 | import { 52 | createClient, 53 | eos 54 | } from "@effectai/sdk"; 55 | const client = await createClient({ network: eos }); 56 | // ---cut--- 57 | import { 58 | getCampaigns 59 | } from "@effectai/sdk"; 60 | 61 | const campaigns = await getCampaigns({ client }); 62 | ``` 63 | 64 | ### 3. Authentication 65 | 66 | Depending on your use case, you might need some sort of authentication with the EOS blockchain. Authentication is done through passing a [Wharfkit Session](https://wharfkit.com/kits/session). Read our guide on [how authenticate depending on your environment](/docs/authentication). 67 | 68 | 69 | ## What's next ? 70 | 71 | Now that we have a basic understanding of how to set up the client, we can move on to more advanced topics, like creating our first data collection campaign. 72 | Read more on the following pages. 73 | 74 | -------------------------------------------------------------------------------- /docs/pages/docs/glossary/types.mdx: -------------------------------------------------------------------------------- 1 | # Types [Glossary of Types in the effect sdk.] 2 | 3 | ## Campaign 4 | 5 | [See Type](https://github.com/effectai/effect-js/blob/main/src/types/campaign.ts) 6 | 7 | ## Client Options 8 | 9 | The ClientOpts interface is used to define the options that can be passed to the EffectAI Client constructor. 10 | 11 | ```typescript 12 | interface ClientOpts { 13 | ipfsCacheDurationInMs?: number | null; 14 | fetchProvider?: FetchProviderOptions; 15 | cacheImplementation?: Cache; 16 | } 17 | ``` 18 | 19 | As we can see, the ClientOpts interface has three optional properties: 20 | 21 | ## `ipfsCacheDurationIMs` 22 | 23 | This property is used to set the cache duration for the IPFS data. 24 | The default value is 600_000 milliseconds; 10 minutes. 25 | 26 | ## `fetchProvider` 27 | 28 | This property is used to set the fetch provider. 29 | This is needed because of the different runtimes availalbe to Java Script. 30 | For example, in older versions of Node.js, the fetch API is not available. 31 | For older versions of Node.js, you can use the [`node-fetch` ](https://github.com/node-fetch/node-fetch) package. 32 | 33 | Since Node.js v18.0.0, the fetch API is available by default. 34 | 35 | In the browser fetch is generally available, and is available on the `window.fetch` object. 36 | You can read more about it here: [MDN Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) 37 | 38 | Other serverside Java Script runtimes such as [Bun](https://bun.sh/) and (Deno)[https://deno.com/] already have fetch available on the global `fetch` object. 39 | 40 | ## `cacheImplementation` 41 | 42 | This property is used to set the cache implementation. 43 | There are three different cache mechanigms abailable in the EffectAI SDK. 44 | First of all, "IDBCache", "LocalStorageCache", "MemoryCache". 45 | Any of these can be passed to the `cacheImplementation` property while instanlizing the EffectAI Client. 46 | 47 | ```typescript 48 | import { createClient, IDBCache, LocalStorageCache, MemoryCache } from '@effectai/sdk' 49 | const client = createClient({ 50 | cacheImplementation: new IDBCache() // or new LocalStorageCache() or new MemoryCache() 51 | }) 52 | ``` 53 | 54 | [See Type](https://github.com/effectai/effect-js/blob/main/src/client.ts) 55 | 56 | ## Asset 57 | 58 | ### Description 59 | 60 | Some functions with the `@effectai/sdk` package will return a `Asset` object. 61 | This object contains information about tokens on the blockchain and contain information such as the symbol, precision, and amount. 62 | 63 | An example for the `Asset` object is as follows: 64 | 65 | 66 | ```json 67 | { 68 | "precision": 4, 69 | "symbol": "EFX", 70 | "units": 10000, 71 | "value": 1 72 | } 73 | ``` 74 | 75 | Read more about the `Asset` object here: 76 | https://wharfkit.com/docs/antelope/asset 77 | 78 | ## Transaction Result 79 | 80 | ### Description 81 | 82 | Some functions with the `@effectai/sdk` package will return a `TransactionResult` object. 83 | This object contains the transaction hash and the transaction receipt. 84 | 85 | The interface for the `TransactionResult` object is as follows: 86 | 87 | 88 | ```ts 89 | interface TransactResult { 90 | chain: ChainDefinition 91 | request: SigningRequest 92 | resolved: ResolvedSigningRequest | undefined 93 | response?: { [key: string]: any } 94 | revisions: TransactRevisions 95 | signatures: Signature[] 96 | signer: PermissionLevel 97 | transaction: ResolvedTransaction | undefined 98 | } 99 | ``` 100 | 101 | Read more about the `TransactionResult` object here: 102 | 103 | https://wharfkit.com/docs/session-kit/transact-result 104 | -------------------------------------------------------------------------------- /docs/pages/docs/introduction.mdx: -------------------------------------------------------------------------------- 1 | # Why Effect AI 2 | 3 | ## Problems 4 | 5 | AI will be the pivotal technology of the future that will transcend us into a new era of efficiency and innovation. 6 | However, the development of AI models is contingent upon the availability of high-quality training data. 7 | This poses a significant challenge, as the creation of such data is a labor-intensive and time-consuming process. 8 | Moreover, this data is often gathered & developed behind closed doors, leading to a lack of transparency and accountability. 9 | 10 | ## Solution 11 | 12 | The solution is Effect AI, a decentralized network that connects AI developers with a global workforce of AI trainers. 13 | Leading the charge in the democratization of AI, Effect AI enables developers to create high-quality training data through a transparent and collaborative process. 14 | By leveraging the power of the crowd, Effect AI ensures that AI models are trained on diverse and reliable datasets, thereby enhancing their accuracy and performance. 15 | -------------------------------------------------------------------------------- /docs/pages/docs/local-development.mdx: -------------------------------------------------------------------------------- 1 | # Local Development -------------------------------------------------------------------------------- /docs/pages/docs/tasks/batches/create-batch.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/batches/create-batch.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/batches/get-batch.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/batches/get-batch.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/campaigns/create-campaign.mdx: -------------------------------------------------------------------------------- 1 | # createCampaign 2 | 3 | ## Description 4 | 5 | This function creates a campaign from a specified client with the given campaign parameters. 6 | You can view the campaign on the [Effect Network](https://app.effect.network/campaigns) before you start collecting data, 7 | you need to add tasks to the campaign. You can do this by following the [Adding Tasks](/docs/collecting-data/adding-tasks) guide. 8 | 9 | ## Usage 10 | 11 | ```ts twoslash 12 | // [!include ~/snippets/tasks/create-campaign.ts] 13 | ``` 14 | ## Output 15 | 16 | ```json 17 | response: { 18 | transaction_id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 19 | processed: { 20 | id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 21 | block_num: 137520447, 22 | block_time: "2024-05-01T03:55:31.500", 23 | producer_block_id: null, 24 | receipt: [Object ...], 25 | elapsed: 4854, 26 | net_usage: 176, 27 | scheduled: false, 28 | action_traces: [ 29 | [Object ...] 30 | ], 31 | account_ram_delta: null, 32 | except: null, 33 | error_code: null, 34 | }, 35 | } 36 | ``` 37 | ## Parameters 38 | 39 | 40 | ### client 41 | - **Type:** `SomeClient` 42 | - **Description:** The client used to retrieve campaigns. 43 | 44 | ### CreateCampaignArgs["campaign"] 45 | - **version**: Version number of the campaign 46 | - **maxTaskTime**: Time maximum time in seconds for the task 47 | - **reward**: Reward for each task in EFX 48 | - **title**: Title of the campaign 49 | - **description**: Description of the campaign 50 | - **instructions**: Instructions for the campaign 51 | - **template**: Template for the campaign, which is a string of HTML 52 | - **input_schema**: JSON schema for each input task 53 | - **output_schema**: JSON schema for each output task 54 | - **image**: Image URL for the campaign 55 | - **category**: Category of the campaign 56 | - **example_task**: An example_task for the campaign, this should be data that will be input into the campaign 57 | - **estimated_time**: Estimated time in seconds for the task 58 | 59 | ## Returns 60 | 61 | **Type:** TransactionResult 62 | 63 | **Description:** 64 | Returns a transaction response object that contains the transaction id block number, and various properties that correlate to the transaction. 65 | Read more about the transaction response here: [TransactionResponse](/docs/glossary/types#transaction-result) 66 | -------------------------------------------------------------------------------- /docs/pages/docs/tasks/campaigns/get-all-campaigns.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/campaigns/get-all-campaigns.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/campaigns/get-campaign-by-id.mdx: -------------------------------------------------------------------------------- 1 | 2 | # getCampaignById 3 | 4 | ## Description 5 | 6 | This function retrieves a campaign from a specified client with the given ID. 7 | 8 | ## Usage 9 | 10 | 11 | ```ts twoslash 12 | // [!include ~/snippets/tasks/get-campaign-by-id.ts] 13 | 14 | ``` 15 | 16 | ## Output 17 | 18 | ```json 19 | { 20 | id: 1, 21 | reservations_done: 1, 22 | total_submissions: 2, 23 | total_tasks: 1, 24 | active_batch: 1, 25 | num_batches: 1, 26 | owner: [ "name", "efxefxefxefx" ], 27 | paused: 0, 28 | content: { 29 | field_0: 0, 30 | field_1: "QmVKwq3bYM6cPW6kstpiq4WYckWRtdfJnzAmms2iMyGqQg", 31 | }, 32 | max_task_time: 3600, 33 | reward: { 34 | quantity: "0.0100 EFX", 35 | contract: "efxtoken1112", 36 | }, 37 | qualis: [], 38 | info: { 39 | version: 1.1, 40 | title: "Labelstudio OCR (LAION)", 41 | description: "You are contributing to a dataset for conversational style chatbots.", 42 | instructions: "Instructions here...", 43 | template: "

Template here...

", 44 | input_schema: null, 45 | output_schema: null, 46 | image: null, 47 | category: null, 48 | example_task: null, 49 | estimated_time: null, 50 | }, 51 | } 52 | ``` 53 | ## Parameters 54 | 55 | ### client 56 | - **Type:** `SomeClient` 57 | - **Description:** The client used to retrieve campaigns. 58 | 59 | ### id 60 | - **Type:** `number` 61 | - **Description:** The campaign id number of the campaign to retrieve. 62 | 63 | ## Returns 64 | 65 | **Type:** [`Promise`](/docs/glossary/types#campaign) 66 | 67 | **Description:** A list of campaigns. 68 | 69 | **Properties:** 70 | 71 | - **id:** Campaign ID. 72 | - **reservations_done:** Number of reservations done for the campaign. 73 | - **total_submissions:** Total number of submissions for the campaign. 74 | - **total_tasks:** Total number of tasks in the campaign. 75 | - **active_batch:** Active batch number. 76 | - **num_batches:** Total number of batches. 77 | - **owner:** Owner of the campaign. 78 | - **paused:** Indicator if the campaign is paused. 79 | - **content:** Campaign content. 80 | - **max_task_time:** Maximum task time in seconds. 81 | - **reward:** Reward information. 82 | - **qualis:** Qualification information. 83 | - **info:** Additional information retrieved from IPFS. 84 | -------------------------------------------------------------------------------- /docs/pages/docs/tasks/campaigns/get-campaigns.mdx: -------------------------------------------------------------------------------- 1 | # getCampaigns 2 | 3 | ## Description 4 | 5 | This function retrieves campaigns from a specified client with optional parameters for pagination, sorting, and IPFS fetching. 6 | 7 | ## Usage 8 | 9 | ```ts twoslash 10 | // [!include ~/snippets/tasks/get-campaigns.ts] 11 | ``` 12 | ## Output 13 | 14 | ```json 15 | { 16 | rows: [ 17 | { 18 | id: 0, 19 | reservations_done: 2, 20 | total_submissions: 2, 21 | total_tasks: 6, 22 | active_batch: 0, 23 | num_batches: 2, 24 | owner: [ "name", "efxefxefxefx" ], 25 | paused: 0, 26 | content: [Object ...], 27 | max_task_time: 3600, 28 | reward: [Object ...], 29 | qualis: [], 30 | info: [Object ...], 31 | }, { */ ... /* }, { */ ... /* } 32 | ], 33 | next_key: UInt128 { */ ... /* }, 34 | more: true, 35 | } 36 | ``` 37 | 38 | 39 | ## Parameters 40 | 41 | ### client 42 | - **Type:** `SomeClient` 43 | - **Description:** The client used to retrieve campaigns. 44 | 45 | ### page 46 | - **Type:** `number` 47 | - **Description:** The page number of the campaigns to retrieve. Default is 1. 48 | 49 | ### limit 50 | - **Type:** `number` 51 | - **Description:** The maximum number of campaigns to retrieve per page. Default is 20. 52 | 53 | ### reverse 54 | - **Type:** `boolean` 55 | - **Description:** Whether to reverse the order of the retrieved campaigns. Default is false. 56 | 57 | ### ipfsFetch 58 | - **Type:** `boolean` 59 | - **Description:** Whether to fetch additional information from IPFS for each campaign. Default is true. 60 | 61 | 62 | ## Returns 63 | 64 | - **Type:** [`Promise>`](/docs/glossary/types#campaign) 65 | - **Description:** A list of campaigns. 66 | - **Properties:** 67 | - **rows:** An array of campaigns with the following structure: 68 | - **id:** Campaign ID. 69 | - **reservations_done:** Number of reservations done for the campaign. 70 | - **total_submissions:** Total number of submissions for the campaign. 71 | - **total_tasks:** Total number of tasks in the campaign. 72 | - **active_batch:** Active batch number. 73 | - **num_batches:** Total number of batches. 74 | - **owner:** Owner of the campaign. 75 | - **paused:** Indicator if the campaign is paused. 76 | - **content:** Campaign content. 77 | - **max_task_time:** Maximum task time in seconds. 78 | - **reward:** Reward information. 79 | - **qualis:** Qualification information. 80 | - **info:** Additional information retrieved from IPFS if enabled. 81 | - **next_key:** A string that can be used to fetch the next page of campaigns. 82 | - **more:** A boolean indicating if there are more campaigns to fetch. 83 | -------------------------------------------------------------------------------- /docs/pages/docs/tasks/get-acc-task-idx.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/get-acc-task-idx.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/get-repetions.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/get-repetions.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/get-submissions.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/get-submissions.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/get-task.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/get-task.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/reservations/get-reservations.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/reservations/get-reservations.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/reservations/reserve-task.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/reservations/reserve-task.mdx -------------------------------------------------------------------------------- /docs/pages/docs/tasks/submit-task.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/tasks/submit-task.mdx -------------------------------------------------------------------------------- /docs/pages/docs/templates/introduction.mdx: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | As described in the previous section, with campaigns, a template is a blueprint that allows you to input data and display it in a specific format. They are the interface used by the workers of EffectAI to interact with the data and perform the tasks required by the client. 4 | 5 | In this section, we will provide an overview of the template engine, explain the basic concepts and components of a template, and guide you through the process of creating your own template. 6 | 7 | We will be creating a simple template that lets users create bounding boxes around objects in an image. This will be done with the help of the open-source data annotation tool called [Label Studio](https://labelstud.io/). 8 | 9 | ## What is a Template? 10 | 11 | A template is some HTML, CSS, and JavaScript code that defines the structure and layout of the data that is to be displayed. It's not a standard HTML5 template that uses the HTML specifications. The template engine is custom-built to handle the data that is to be displayed in the template. 12 | 13 | There is an existing HTML document, with a head and body tag defined with the requirements for EffectAI. What we need is to add what you would usually add in the body of the document. 14 | 15 | So the simplest template, which is just a text template, would look like this: 16 | 17 | ```html 18 |
19 |

Hello World!

20 |
21 | ``` 22 | 23 | This is a simple template that displays the text "Hello World!" in a paragraph tag. But the main issue here is that we still need to load in dynamic data from a data source so that each task is different. 24 | 25 | ## Parameterizing Templates: Placeholders 26 | 27 | In order to be able to use the same template for different data, we need to parameterize the template. This means that we need to define placeholders in the template that will be replaced with the actual data when the template is rendered. 28 | 29 | The way this is done in EffectAI is by using the `${}` syntax. This is similar to the way you would use template literals in JavaScript. 30 | 31 | For example, if we want to display the name of a person in the template, we would define a placeholder like this: 32 | 33 | ```html 34 |
35 |

Hello ${name}!

36 |
37 | ``` 38 | 39 | When the template is rendered, the `${name}` placeholder will be replaced with the actual name of the person. 40 | 41 | ## Submitting Templates and Retrieving Results 42 | 43 | So now we understand how to input data into the template, but how do we get results back? Workers on EffectAI will get a rendered template with the data inputted into the template. The worker will then perform the task required by the client and submit the result. 44 | 45 | Submitting is a standard submit event in HTML, but the data is saved in the EffectAI smart contracts. 46 | 47 | Here's an example of a form with an input field and a submit button: 48 | 49 | ```html 50 |

Placeholder example: ${placeholder}

51 | 52 | 53 | ``` 54 | 55 | When we input the text "World" into the text field and submit this, we get the following submission: 56 | 57 | ```json 58 | { 59 | "test": "World" 60 | } 61 | ``` 62 | 63 | ## Creating Your Own Template 64 | 65 | You can try out the templates for yourself by inputting them into [EffectAI's template preview tool](https://app.effect.network/preview/). 66 | 67 | 68 | -------------------------------------------------------------------------------- /docs/pages/docs/templates/labelstudio.mdx: -------------------------------------------------------------------------------- 1 | # Label Studio example 2 | 3 | Here we will show an example of how to use [Label Studio](https://labelstud.io/) to label images for object detection. 4 | 5 | ![Example](/labelstudioocr.png) 6 | 7 | As discussed before we will be using the Label Studio to create a labeling task for object detection. 8 | Here is an example of how to use Label Studio to create a labeling task for object detection. 9 | We have some HTML tags, that contain style sheets, the div that will be the container for Label Studio, library and scripts to initialize Label Studio. 10 | 11 | 12 | ## Template 13 | ```html 14 | // [!include ~/snippets/templates/index.html] 15 | ``` 16 | 17 | ## Input Schema 18 | 19 | Note that you can also define the input and output schema for a given template. 20 | This will allow you to define the structure of the data that will be used in the labeling task and the output that will be generated by the annotators. 21 | 22 | {/* TODO figure out how to shorten this schema and make it more readable */} 23 | 24 | ```json 25 | // [!include ~/snippets/templates/input_schema.json] 26 | ``` 27 | ## Example output data 28 | 29 | This is what the output data will look like after the annotators have labeled the images. 30 | 31 | {/* TODO figure out how to shorten this example and make it more readable */} 32 | 33 | 34 | ```json 35 | // [!include ~/snippets/templates/example.json] 36 | ``` 37 | 38 | ## Script 39 | 40 | You can use the following script to initialize Label Studio and create a labeling task for object detection. 41 | This script uses [bun.sh](https://bun.sh/). 42 | 43 | ```typescript 44 | // [!include ~/snippets/templates/script.ts] 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /docs/pages/docs/templates/placeholders.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/templates/placeholders.mdx -------------------------------------------------------------------------------- /docs/pages/docs/token/get-balance.mdx: -------------------------------------------------------------------------------- 1 | # getBalance 2 | 3 | ## Description 4 | 5 | This function is used to return the blance of EFX, USDT, and EOS of an account on the EOS blockchain. 6 | Namely the balance is what is available in the wallet of the user. 7 | 8 | There is a difference between the balance of EFX of an account that is available in the wallet of the user and the balance of EFX that is available in an Effect Network Virtual Account. 9 | To retrieve the EFX balance of a user in their Virtual Account, use the [getVaccount](/docs/vaccount/get-accounts.mdx) 10 | 11 | 12 | ## Usage 13 | 14 | ```ts twoslash 15 | // [!include ~/snippets/token/get-balance.ts] 16 | ``` 17 | 18 | ## Output 19 | 20 | ``` 21 | 378332.1630 EFX 22 | 26.7212 USDT 23 | 31.3322 EOS 24 | ``` 25 | ## Parameters 26 | 27 | ### Client 28 | - **Type:** `Client` 29 | - **Description:** Client object that is used to interact with the blockchain. 30 | 31 | ### Actor 32 | 33 | - **Type:** `Name` 34 | - **Description:** 35 | The account name of the user for which the balance is to be fetched. 36 | Note that the account name is a Name object that is created using the `Name.from` method. 37 | 38 | ## Returns 39 | 40 | **Type:** `{ efxBalance: Asset; usdtBalance: Asset; eosBalance: Asset; }` 41 | 42 | **Description:** 43 | Return an object with three properties: `efxBalance`, `usdtBalance`, and `eosBalance`, each of which is an Asset object. 44 | The asset object has properties that represent the amount and symbol of the balance of the user. 45 | Note that the Asset object has a `toString` method that can be used to convert the balance to a string. 46 | 47 | You can read more about the: [`Asset` object](/docs/glossary/types#asset) 48 | -------------------------------------------------------------------------------- /docs/pages/docs/token/get-price.mdx: -------------------------------------------------------------------------------- 1 | # getPrice 2 | 3 | ## Description 4 | 5 | By calling this function, you will get the current price of the EFX token according to DefiBox. 6 | The price is in USDT. The contract can be viewed at the following link: https://www.bloks.io/account/tethertether 7 | It is not needed for this function to connect a client or a session. 8 | 9 | 10 | ## Usage 11 | 12 | ```ts twoslash 13 | 14 | // [!include ~/snippets/token/get-price.ts] 15 | ``` 16 | 17 | ## Output 18 | 19 | ``` 20 | 0.023399935809187228 21 | ``` 22 | ## Parameters 23 | 24 | ### N.A. 25 | - **Description:** No parameters required for this function 26 | 27 | ## Returns 28 | 29 | **Type:** Number 30 | 31 | **Description:** The current price of the EFX token according to DefiBox in USDT. 32 | 33 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/claim.mdx: -------------------------------------------------------------------------------- 1 | # claim 2 | 3 | ## Description 4 | 5 | This function is used to claim the task reward that is locked in the escrow for the done tasks. 6 | Every time a task is done, the reward is locked in the escrow until the timeout is reached. 7 | After the timeout is reached, the reward can be claimed by the user who did the task. 8 | The resulting EFX will be transferred to the user's VAccount. 9 | The main difference between claim and payout, is where the funds are sent. 10 | 11 | ## Usage 12 | 13 | ```ts twoslash 14 | 15 | // [!include ~/snippets/vaccount/claim.ts] 16 | ``` 17 | 18 | ## Output 19 | 20 | ```json 21 | response: { 22 | transaction_id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 23 | processed: { 24 | id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 25 | block_num: 137520447, 26 | block_time: "2024-05-01T03:55:31.500", 27 | producer_block_id: null, 28 | receipt: [Object ...], 29 | elapsed: 4854, 30 | net_usage: 176, 31 | scheduled: false, 32 | action_traces: [ 33 | [Object ...] 34 | ], 35 | account_ram_delta: null, 36 | except: null, 37 | error_code: null, 38 | }, 39 | } 40 | ``` 41 | 42 | ## Parameters 43 | 44 | ### Client 45 | - **Description:** The client object, **must** be connected with a Session, so that only the user with their wallet can claim the rewards. 46 | 47 | ## Returns 48 | 49 | **Type:** TransactionResult 50 | 51 | **Description:** 52 | Returns a transaction response object that contains the transaction id block number, and various properties that correlate to the transaction. 53 | Read more about the transaction response here: [TransactionResponse](/docs/glossary/types#transaction-result) 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/create-account.mdx: -------------------------------------------------------------------------------- 1 | # createAccount 2 | 3 | ## Description 4 | 5 | Next to having an EOS account, users will also need to create an Effect Network Virtual account, also known as a VAccount. 6 | This virtual account is used to store the user's funds and is used to pay for services on the Effect Network. 7 | The vAccount system is controled by the smart contract found at: [https://www.bloks.io/account/vaccount.efx](https://www.bloks.io/account/vaccount.efx) 8 | 9 | This function will create a new vAccount for the user, and will return the transaction response object. 10 | 11 | 12 | ## Usage 13 | 14 | ```ts twoslash 15 | 16 | // [!include ~/snippets/vaccount/create-account.ts] 17 | ``` 18 | 19 | ## Output 20 | 21 | ```json 22 | response: { 23 | transaction_id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 24 | processed: { 25 | id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 26 | block_num: 137520447, 27 | block_time: "2024-05-01T03:55:31.500", 28 | producer_block_id: null, 29 | receipt: [Object ...], 30 | elapsed: 4854, 31 | net_usage: 176, 32 | scheduled: false, 33 | action_traces: [ 34 | [Object ...] 35 | ], 36 | account_ram_delta: null, 37 | except: null, 38 | error_code: null, 39 | }, 40 | } 41 | ``` 42 | 43 | ## Parameters 44 | 45 | ### Client 46 | - **Description:** The client object, **must** be connected with a Session. 47 | 48 | ### Actor 49 | - **Description:** The actor name, from which the PendinPayments should be claimed and paid out. 50 | 51 | ## Returns 52 | 53 | **Type:** TransactionResult 54 | 55 | **Description:** 56 | Returns a transaction response object that contains the transaction id block number, and various properties that correlate to the transaction. 57 | Read more about the transaction response here: [TransactionResponse](/docs/glossary/types#transaction-result) 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/deposit.mdx: -------------------------------------------------------------------------------- 1 | # deposit 2 | 3 | ## Description 4 | 5 | User are able to deposit funds into their vAccount or claim the funds from escrow and have them deposited in to their vAccount. 6 | Depositing funds into the vAccount is nessesary to be able to pay for creating campaigns, batches and tasks. 7 | 8 | ## Usage 9 | 10 | ```ts twoslash 11 | 12 | // [!include ~/snippets/vaccount/deposit.ts] 13 | ``` 14 | 15 | ## Output 16 | 17 | ```json 18 | response: { 19 | transaction_id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 20 | processed: { 21 | id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 22 | block_num: 137520447, 23 | block_time: "2024-05-01T03:55:31.500", 24 | producer_block_id: null, 25 | receipt: [Object ...], 26 | elapsed: 4854, 27 | net_usage: 176, 28 | scheduled: false, 29 | action_traces: [ 30 | [Object ...] 31 | ], 32 | account_ram_delta: null, 33 | except: null, 34 | error_code: null, 35 | }, 36 | } 37 | ``` 38 | 39 | ## Parameters 40 | 41 | ### Client 42 | - **Description:** The client object, **must** be connected with a Session. 43 | 44 | ### vAccountId 45 | - **Description:** The vAccount id, where the funds should be deposited. 46 | 47 | 48 | ### amount 49 | - **Description:** The amount of funds to be deposited. 50 | 51 | ## Returns 52 | 53 | **Type:** TransactionResult 54 | 55 | **Description:** 56 | Returns a transaction response object that contains the transaction id block number, and various properties that correlate to the transaction. 57 | Read more about the transaction response here: [TransactionResponse](/docs/glossary/types#transaction-result) 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/get-accounts.mdx: -------------------------------------------------------------------------------- 1 | 2 | # getVaccounts 3 | 4 | ## Description 5 | 6 | Next to having an EOS account, users will also need to create an Effect Network Virtual account, also known as a VAccount. 7 | This virtual account is used to store the user's funds and is used to pay for services on the Effect Network. 8 | The vAccount system is controled by the smart contract found at: [https://www.bloks.io/account/vaccount.efx](https://www.bloks.io/account/vaccount.efx) 9 | 10 | This function will return the vAccounts associated with the actor name provided. 11 | 12 | 13 | ## Usage 14 | 15 | ```ts twoslash 16 | 17 | // [!include ~/snippets/vaccount/get-accounts.ts] 18 | ``` 19 | 20 | ## Output 21 | 22 | ```json 23 | { 24 | id: 24, 25 | nonce: 19, 26 | address: [ "name", "forcedev1234" ], 27 | balance: { 28 | quantity: "2.0981 EFX", 29 | contract: "efxtoken1112", 30 | }, 31 | } 32 | ``` 33 | 34 | ## Parameters 35 | 36 | ### Client 37 | - **Description:** The client object, **must** be connected with a Session. 38 | 39 | ### Actor 40 | - **Description:** The actor name, from which the PendinPayments should be claimed and paid out. 41 | 42 | ## Returns 43 | 44 | **Type:** Vaccount 45 | 46 | **Description:** 47 | An object representing a Vaccount, containing the following fields: 48 | - **id**: The id of the vAccount. 49 | - **nonce**: The nonce of the vAccount. 50 | - **address**: The address of the vAccount. 51 | - **balance**: The balance of the vAccount, containing the following fields: 52 | - **quantity**: The amount of EFX tokens in the vAccount. 53 | - **contract**: The contract of the EFX tokens in the vAccount. 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/get-avatar.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/vaccount/get-avatar.mdx -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/get-or-create.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/vaccount/get-or-create.mdx -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/get-pending-payments.mdx: -------------------------------------------------------------------------------- 1 | # getPendinPayments 2 | 3 | ## Description 4 | 5 | Every time a user completes a task, EFX tokens are unlocked from the task, and put into escrow for the Vaccount. This function returns the pending payments for a given Vaccount. 6 | Thus the Vaccount can claim the pending payments, and pay then out to the user when the unlock period has passed. 7 | 8 | 9 | ## Usage 10 | 11 | ```ts twoslash 12 | // [!include ~/snippets/vaccount/get-pending-payments.ts] 13 | ``` 14 | 15 | ## Output 16 | 17 | ```json 18 | { 19 | pendingPayments: [], 20 | claimablePayments: [], 21 | totalEfxPending: 0, 22 | totalEfxClaimable: 0, 23 | } 24 | ``` 25 | 26 | ## Parameters 27 | 28 | ### Client 29 | - **Description:** The client object, **must** be connected with a Session. 30 | 31 | ### vAccountId 32 | - **Description:** The id of the vAccount. 33 | 34 | ## Returns 35 | 36 | **Type:** An object containing the following fields: 37 | 38 | - **pendingPayments** 39 | - **Type:** Array of objects 40 | - **Description:** An array of objects containing the pending payments for the Vaccount. 41 | 42 | - **claimablePayments** 43 | - **Type:** Array of objects 44 | - **Description:** An array of objects containing the claimable payments for the Vaccount. 45 | 46 | - **totalEfxPending** 47 | - **Type:** Number 48 | - **Description:** The total amount of EFX pending for the Vaccount. 49 | 50 | - **totalEfxClaimable** 51 | - **Type:** Number 52 | - **Description:** The total amount of EFX claimable for the Vaccount. 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/payout.mdx: -------------------------------------------------------------------------------- 1 | # payout 2 | 3 | ## Description 4 | 5 | This function is used to claim the task reward that is locked in the escrow for the done tasks. 6 | Every time a task is done, the reward is locked in the escrow until the timeout is reached. 7 | After the timeout is reached, the reward can be claimed by the user who did the task. 8 | The resulting EFX will be transferred to the user's EOS account on the blockchain. 9 | 10 | The main difference between claim and payout, is where the funds are sent. 11 | 12 | ## Usage 13 | 14 | ```ts twoslash 15 | 16 | // [!include ~/snippets/vaccount/payout.ts] 17 | ``` 18 | 19 | ## Output 20 | 21 | ```json 22 | response: { 23 | transaction_id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 24 | processed: { 25 | id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 26 | block_num: 137520447, 27 | block_time: "2024-05-01T03:55:31.500", 28 | producer_block_id: null, 29 | receipt: [Object ...], 30 | elapsed: 4854, 31 | net_usage: 176, 32 | scheduled: false, 33 | action_traces: [ 34 | [Object ...] 35 | ], 36 | account_ram_delta: null, 37 | except: null, 38 | error_code: null, 39 | }, 40 | } 41 | ``` 42 | 43 | ## Parameters 44 | 45 | ### Client 46 | - **Description:** The client object, **must** be connected with a Session. 47 | 48 | ### Actor 49 | - **Description:** The actor name, from which the PendinPayments should be claimed and paid out. 50 | 51 | ## Returns 52 | 53 | **Type:** TransactionResult 54 | 55 | **Description:** 56 | Returns a transaction response object that contains the transaction id block number, and various properties that correlate to the transaction. 57 | Read more about the transaction response here: [TransactionResponse](/docs/glossary/types#transaction-result) 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/transfer.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/pages/docs/vaccount/transfer.mdx -------------------------------------------------------------------------------- /docs/pages/docs/vaccount/withdraw.mdx: -------------------------------------------------------------------------------- 1 | # withdraw 2 | 3 | ## Description 4 | 5 | User are able to deposit funds into their vAccount or claim the funds from escrow and have them deposited in to their vAccount. 6 | These funds can be withdrawn to the user's wallet by calling the withdraw action. 7 | 8 | 9 | ## Usage 10 | 11 | ```ts twoslash 12 | 13 | // [!include ~/snippets/vaccount/withdraw.ts] 14 | ``` 15 | 16 | ## Output 17 | 18 | ```json 19 | response: { 20 | transaction_id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 21 | processed: { 22 | id: "9d321af28b7354c5cbee6ee956ea3e6590228b48539a9f0cafc6a8ca5ffe0ca2", 23 | block_num: 137520447, 24 | block_time: "2024-05-01T03:55:31.500", 25 | producer_block_id: null, 26 | receipt: [Object ...], 27 | elapsed: 4854, 28 | net_usage: 176, 29 | scheduled: false, 30 | action_traces: [ 31 | [Object ...] 32 | ], 33 | account_ram_delta: null, 34 | except: null, 35 | error_code: null, 36 | }, 37 | } 38 | ``` 39 | 40 | ## Parameters 41 | 42 | ### Client 43 | - **Description:** The client object, **must** be connected with a Session. 44 | 45 | ### Actor 46 | - **Description:** The actor name, from which the PendinPayments should be claimed and paid out. 47 | 48 | ## Returns 49 | 50 | **Type:** TransactionResult 51 | 52 | **Description:** 53 | Returns a transaction response object that contains the transaction id block number, and various properties that correlate to the transaction. 54 | Read more about the transaction response here: [TransactionResponse](/docs/glossary/types#transaction-result) 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/public/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/public/.nojekyll -------------------------------------------------------------------------------- /docs/public/CNAME: -------------------------------------------------------------------------------- 1 | docs.effect.ai -------------------------------------------------------------------------------- /docs/public/effect-logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/public/effect-logo-black.png -------------------------------------------------------------------------------- /docs/public/effect_template_placeholder_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/public/effect_template_placeholder_example.png -------------------------------------------------------------------------------- /docs/public/labelstudioocr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/public/labelstudioocr.png -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/public/logo.png -------------------------------------------------------------------------------- /docs/public/preview-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/docs/public/preview-bg.png -------------------------------------------------------------------------------- /docs/sidebar.ts: -------------------------------------------------------------------------------- 1 | import type { Sidebar } from "vocs"; 2 | 3 | export const sidebar = { 4 | "/docs/": [ 5 | { 6 | text: "Introduction", 7 | items: [ 8 | { text: "Why Effect AI", link: "/docs/introduction" }, 9 | { text: "Getting Started", link: "/docs/getting-started" }, 10 | { text: "Authentication", link: "/docs/authentication" }, 11 | ], 12 | }, 13 | { 14 | text: "Collecting Data", 15 | items: [ 16 | { text: "Introduction", link: "/docs/collecting-data/introduction" }, 17 | { 18 | text: "Creating a Template", 19 | link: "/docs/collecting-data/create-a-template", 20 | }, 21 | { 22 | text: "Creating a Campaign", 23 | link: "/docs/collecting-data/create-a-campaign", 24 | }, 25 | { 26 | text: "Adding Tasks to a Campaign", 27 | link: "/docs/collecting-data/adding-tasks", 28 | }, 29 | { 30 | text: "Collecting results", 31 | link: "/docs/collecting-data/collecting-results", 32 | }, 33 | ], 34 | }, 35 | { 36 | text: "Templates", 37 | items: [ 38 | { text: "Introduction", link: "/docs/templates/introduction" }, 39 | { text: "Label-Studio", link: "/docs/templates/labelstudio" }, 40 | ], 41 | }, 42 | 43 | { 44 | text: "SDK API", 45 | collapsed: true, 46 | items: [ 47 | { 48 | text: "Tasks", 49 | items: [ 50 | { 51 | text: "createCampaign", 52 | link: "/docs/tasks/campaigns/create-campaign", 53 | }, 54 | { 55 | text: "getCampaigns", 56 | link: "/docs/tasks/campaigns/get-campaigns", 57 | }, 58 | { 59 | text: "getCampaignById", 60 | link: "/docs/tasks/campaigns/get-campaign-by-id", 61 | }, 62 | ], 63 | }, 64 | { 65 | text: "Token", 66 | items: [ 67 | { text: "getPrice", link: "/docs/token/get-price" }, 68 | { text: "getBalance", link: "/docs/token/get-balance" }, 69 | { text: "transfer", link: "/docs/token/transfer" }, 70 | { text: "swap", link: "/docs/token/swap" }, 71 | ], 72 | }, 73 | { 74 | text: "vAccount", 75 | items: [ 76 | { text: "claim", link: "/docs/vaccount/claim" }, 77 | { 78 | text: "createAccount", 79 | link: "/docs/vaccount/create-account", 80 | }, 81 | { text: "deposit", link: "/docs/vaccount/deposit" }, 82 | { 83 | text: "getVAccounts", 84 | link: "/docs/vaccount/get-accounts", 85 | }, 86 | // { 87 | // text: "TODO: getAvatar", 88 | // link: "/docs/vaccount/get-avatar", 89 | // }, 90 | { 91 | text: "getPendingPayments", 92 | link: "/docs/vaccount/get-pending-payments", 93 | }, 94 | { text: "payout", link: "/docs/vaccount/payout" }, 95 | { text: "withdraw", link: "/docs/vaccount/withdraw" }, 96 | ], 97 | }, 98 | // { 99 | // text: "DAO", 100 | // items: [ 101 | // { 102 | // text: "TODO: getAccountAssets", 103 | // link: "/docs/tasks/dao/get-account-assets", 104 | // }, 105 | // ], 106 | // }, 107 | ], 108 | }, 109 | { 110 | text: "Glossary", 111 | items: [ 112 | { text: "Terminology", link: "/docs/glossary/terminology" }, 113 | { text: "Types", link: "/docs/glossary/types" }, 114 | ], 115 | }, 116 | { 117 | text: "FAQ", 118 | items: [{ text: "FAQ", link: "/docs/faq" }], 119 | }, 120 | ], 121 | } as const satisfies Sidebar; 122 | -------------------------------------------------------------------------------- /docs/snippets/getting-started/getting-started-auth.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | jungle4 as network, 5 | // eos as network , // Use `eos` to use mainnet 6 | Session, 7 | createVAccount, 8 | } from "@effectai/sdk"; 9 | 10 | // Set up session with wallet and chain 11 | const session = new Session({ 12 | actor: "account_name_here", 13 | permission: "permission_here", 14 | walletPlugin: new WalletPluginPrivateKey("your_private_key_here"), 15 | chain: network, 16 | }); 17 | 18 | // Create client to make authenticated transactions 19 | const client = await createClient({ session }); 20 | -------------------------------------------------------------------------------- /docs/snippets/getting-started/getting-started-init.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createClient, 3 | jungle4 as network, 4 | // eos as network , // Use `eos` to use mainnet 5 | } from "@effectai/sdk"; 6 | 7 | // Create client 8 | const client = await createClient({ network }); 9 | -------------------------------------------------------------------------------- /docs/snippets/getting-started/getting-started-nonauth.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createClient, 3 | jungle4 as network, 4 | // eos as network , // Use `eos` to use mainnet 5 | getAccountById, 6 | } from "@effectai/sdk"; 7 | 8 | // Create client to make unauthenticated transactions 9 | const client = await createClient({ network }); 10 | 11 | // Retrieve data from Effect Network 12 | const vAccount = await getAccountById({ client, accountId: 1 }); 13 | console.log(vAccount); // => Account Details 14 | -------------------------------------------------------------------------------- /docs/snippets/tasks/create-campaign.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { Session, jungle4 as chain, createClient } from "@effectai/sdk"; 3 | 4 | const session = new Session({ 5 | actor: "your-account", 6 | permission: "permission-level", 7 | chain, 8 | walletPlugin: new WalletPluginPrivateKey("your-private-key"), 9 | }); 10 | 11 | const client = await createClient({ session }); 12 | // ---cut--- 13 | import { createCampaign } from "@effectai/sdk"; 14 | 15 | const campaign = await createCampaign({ 16 | client, 17 | campaign: { 18 | // Name of your campaign 19 | title: "My First Campaign!", 20 | // Description of the campaign 21 | description: "Description of the task here.", 22 | // Campaign version 23 | version: 1.0, 24 | // Maximum time to complete a task in seconds 25 | maxTaskTime: 100, 26 | // EFX reward per task 27 | reward: 3.5, 28 | // Custom instructions for completing tasks in this campaign (Markdown supported) 29 | instructions: "Some instructions here", 30 | // Template of the campaign see https://docs.effect.ai/docs/templates/introduction 31 | template: "

Template here

", 32 | // Input schema to validate the task data. 33 | input_schema: null, 34 | // TODO:: 35 | output_schema: null, 36 | // Image URL for the campaign 37 | image: "", 38 | // Category of the campaign 39 | category: "", 40 | // TODO:: 41 | example_task: "", 42 | // TODO:: Estimated time to complete a task in this campaign 43 | estimated_time: 10, 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /docs/snippets/tasks/get-campaign-by-id.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type Campaign, 3 | type CampaignWithInfo, 4 | createClient, 5 | getCampaignById, 6 | jungle4 as network, 7 | } from "@effectai/sdk"; 8 | 9 | const client = await createClient({ network }); 10 | const campaign = await getCampaignById({ client, id: 1 }); 11 | -------------------------------------------------------------------------------- /docs/snippets/tasks/get-campaigns.ts: -------------------------------------------------------------------------------- 1 | import { createClient, getCampaigns, jungle4 as network } from "@effectai/sdk"; 2 | 3 | const client = await createClient({ network }); 4 | const campaigns = await getCampaigns({ client }); 5 | console.log(campaigns); 6 | -------------------------------------------------------------------------------- /docs/snippets/templates/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "created_at": "2021-03-09T21:52:49.513742Z", 4 | "updated_at": "2021-03-09T22:16:08.746926Z", 5 | "project": 83, 6 | 7 | "data": { 8 | "image": "https://example.com/opensource/label-studio/1.jpg" 9 | }, 10 | 11 | "annotations": [ 12 | { 13 | "id": "1001", 14 | "result": [ 15 | { 16 | "from_name": "tag", 17 | "id": "Dx_aB91ISN", 18 | "source": "$image", 19 | "to_name": "img", 20 | "type": "rectanglelabels", 21 | "value": { 22 | "height": 10.458911419423693, 23 | "rectanglelabels": ["Moonwalker"], 24 | "rotation": 0, 25 | "width": 12.4, 26 | "x": 50.8, 27 | "y": 5.869797225186766 28 | } 29 | } 30 | ], 31 | "was_cancelled": false, 32 | "ground_truth": false, 33 | "created_at": "2021-03-09T22:16:08.728353Z", 34 | "updated_at": "2021-03-09T22:16:08.728378Z", 35 | "lead_time": 4.288, 36 | "result_count": 0, 37 | "task": 1, 38 | "completed_by": 10 39 | } 40 | ], 41 | 42 | "predictions": [ 43 | { 44 | "created_ago": "3 hours", 45 | "model_version": "model 1", 46 | "result": [ 47 | { 48 | "from_name": "tag", 49 | "id": "t5sp3TyXPo", 50 | "source": "$image", 51 | "to_name": "img", 52 | "type": "rectanglelabels", 53 | "value": { 54 | "height": 11.612284069097889, 55 | "rectanglelabels": ["Moonwalker"], 56 | "rotation": 0, 57 | "width": 39.6, 58 | "x": 13.2, 59 | "y": 34.702495201535505 60 | } 61 | } 62 | ] 63 | }, 64 | { 65 | "created_ago": "4 hours", 66 | "model_version": "model 2", 67 | "result": [ 68 | { 69 | "from_name": "tag", 70 | "id": "t5sp3TyXPo", 71 | "source": "$image", 72 | "to_name": "img", 73 | "type": "rectanglelabels", 74 | "value": { 75 | "height": 33.61228406909789, 76 | "rectanglelabels": ["Moonwalker"], 77 | "rotation": 0, 78 | "width": 39.6, 79 | "x": 13.2, 80 | "y": 54.702495201535505 81 | } 82 | } 83 | ] 84 | } 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /docs/snippets/templates/input_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "id": { 6 | "type": "string" 7 | }, 8 | "annotations": { 9 | "type": "array", 10 | "items": { 11 | "type": "object", 12 | "properties": { 13 | "id": { 14 | "type": "string" 15 | }, 16 | "result": { 17 | "type": "array", 18 | "items": { 19 | "type": "object", 20 | "properties": { 21 | "original_width": { 22 | "type": "integer" 23 | }, 24 | "original_height": { 25 | "type": "integer" 26 | }, 27 | "image_rotation": { 28 | "type": "integer" 29 | }, 30 | "value": { 31 | "type": "object", 32 | "properties": { 33 | "x": { 34 | "type": "number" 35 | }, 36 | "y": { 37 | "type": "number" 38 | }, 39 | "width": { 40 | "type": "number" 41 | }, 42 | "height": { 43 | "type": "number" 44 | }, 45 | "rotation": { 46 | "type": "integer" 47 | }, 48 | "text": { 49 | "type": "array", 50 | "items": { 51 | "type": "string" 52 | } 53 | } 54 | }, 55 | "required": ["x", "y", "width", "height", "rotation"] 56 | }, 57 | "from_name": { 58 | "type": "string" 59 | }, 60 | "to_name": { 61 | "type": "string" 62 | }, 63 | "type": { 64 | "type": "string" 65 | } 66 | }, 67 | "required": [ 68 | "original_width", 69 | "original_height", 70 | "image_rotation", 71 | "value", 72 | "from_name", 73 | "to_name", 74 | "type" 75 | ] 76 | } 77 | } 78 | }, 79 | "required": ["id", "result"] 80 | } 81 | }, 82 | "data": { 83 | "type": "object", 84 | "properties": { 85 | "image": { 86 | "type": "string" 87 | } 88 | }, 89 | "required": ["image"] 90 | } 91 | }, 92 | "required": ["id", "annotations", "data"] 93 | } 94 | -------------------------------------------------------------------------------- /docs/snippets/templates/script.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | createCampaign, 5 | eos, 6 | Session, 7 | type CreateCampaignArgs, 8 | } from "@effectai/sdk"; 9 | 10 | const campaignFile = Bun.file("index.html"); 11 | const inputSchema = Bun.file("input-schema.json"); 12 | const exampleTask = Bun.file("example.json"); 13 | 14 | const session = new Session({ 15 | chain: eos, 16 | actor: "your_account", 17 | permission: "your_permission", 18 | walletPlugin: new WalletPluginPrivateKey("your_private_key"), 19 | }); 20 | 21 | const client = await createClient({ session }); 22 | 23 | const campaign: CreateCampaignArgs = { 24 | client: client, 25 | campaign: { 26 | category: "category", 27 | description: "Description for this Campaign", 28 | estimated_time: 1, 29 | example_task: exampleTask.toString(), 30 | image: "image", 31 | instructions: "Instructions for this Camapign", 32 | input_schema: inputSchema.toString(), 33 | output_schema: null, 34 | template: campaignFile.toString(), 35 | title: "Title for this Campaign", 36 | version: 1, 37 | reward: 1, 38 | maxTaskTime: 1, 39 | qualifications: [], 40 | }, 41 | }; 42 | 43 | const response = createCampaign(campaign); 44 | console.debug(response); 45 | -------------------------------------------------------------------------------- /docs/snippets/token/get-balance.ts: -------------------------------------------------------------------------------- 1 | import { createClient, eos, getBalance, jungle4 } from "@effectai/sdk"; 2 | 3 | const client = await createClient({ network: eos }); 4 | const actor = "cryptonode42"; 5 | const balance = await getBalance({ client, actor }); 6 | console.log( 7 | balance.efxBalance.toString(), 8 | balance.usdtBalance.toString(), 9 | balance.eosBalance.toString(), 10 | ); 11 | -------------------------------------------------------------------------------- /docs/snippets/token/get-price.ts: -------------------------------------------------------------------------------- 1 | import { getPrice } from "@effectai/sdk"; 2 | const price = await getPrice(); 3 | console.log(price); 4 | -------------------------------------------------------------------------------- /docs/snippets/token/swap.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | jungle4 as chain, 5 | // eos as chain, 6 | Session, 7 | swap, 8 | type SwapArgs, 9 | getBalance, 10 | } from "@effectai/sdk"; 11 | 12 | const actor = "actor-name"; 13 | const permission = "permission-level"; 14 | 15 | // Create a session 16 | const session = new Session({ 17 | chain, 18 | actor, 19 | permission, 20 | walletPlugin: new WalletPluginPrivateKey("your_private_key"), 21 | }); 22 | 23 | // Create client and connect session 24 | const client = await createClient({ session }); 25 | 26 | // Define the swap arguments 27 | const swapArgs: SwapArgs = { 28 | client, 29 | amount: 4, // Define amount, up to 4 digits behind the decimal 30 | direction: "UsdtToEfx", // or "EfxToUsdt" 31 | }; 32 | 33 | const preBalance = await getBalance({ client, actor }); 34 | 35 | // Call the swap function 36 | const response = await swap(swapArgs); 37 | -------------------------------------------------------------------------------- /docs/snippets/token/transfer.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createClient, 3 | jungle4 as network, 4 | vTransfer, 5 | getVAccounts, 6 | } from "@effectai/sdk"; 7 | 8 | const client = await createClient({ network }); 9 | const receiver = "receiver-account-name"; 10 | 11 | const [vAccountReceiver] = await getVAccounts({ 12 | client, 13 | actor: receiver, 14 | }); 15 | 16 | const result = await vTransfer({ 17 | client, 18 | to_id: vAccountReceiver.id, 19 | quantity: 12, 20 | }); 21 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/claim.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | jungle4 as chain, 5 | // eos as chain, 6 | Session, 7 | claim, 8 | type ClaimArgs, 9 | getPendingPayments, 10 | getVAccounts, 11 | } from "@effectai/sdk"; 12 | 13 | const actor = "actor-name"; 14 | const permission = "permission-level"; 15 | 16 | // Create a session 17 | const session = new Session({ 18 | chain, 19 | actor, 20 | permission, 21 | walletPlugin: new WalletPluginPrivateKey("your_private_key"), 22 | }); 23 | 24 | // Create client and connect session 25 | const client = await createClient({ session }); 26 | 27 | const [vacc] = await getVAccounts({ client, actor }); 28 | 29 | // Check pending payments 30 | const pendingPayments = await getPendingPayments({ 31 | client, 32 | vAccountId: vacc.id, 33 | }); 34 | 35 | // If there are claimable payments, claim them. 36 | if (pendingPayments.totalEfxClaimable > 0) { 37 | await claim({ client }); 38 | } 39 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/create-account.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | jungle4 as chain, 5 | // eos as chain, 6 | Session, 7 | createVAccount, 8 | type CreateVAccountArgs, 9 | getVAccounts, 10 | } from "@effectai/sdk"; 11 | 12 | const actor = "actor-name"; 13 | const permission = "permission-level"; 14 | 15 | // Create a session 16 | const session = new Session({ 17 | chain, 18 | actor, 19 | permission, 20 | walletPlugin: new WalletPluginPrivateKey("your_private_key"), 21 | }); 22 | 23 | // Create client and connect session 24 | const client = await createClient({ session }); 25 | const account = "account-name"; 26 | const tx_result = await createVAccount({ client, account }); 27 | console.log(tx_result); 28 | 29 | // Retrieve the created vaccount 30 | const [vacc] = await getVAccounts({ client, actor: account }); 31 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/deposit.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createClient, 3 | jungle4 as network, 4 | getVAccounts, 5 | deposit, 6 | type DepositArgs, 7 | } from "@effectai/sdk"; 8 | 9 | const client = await createClient({ network }); 10 | const actor = "account-name"; 11 | const [vAccount] = await getVAccounts({ client, actor }); 12 | const result = await deposit({ client, vAccountId: vAccount.id, amount: 0.1 }); 13 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/get-accounts.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createClient, 3 | jungle4 as network, 4 | // eos as network, 5 | getVAccounts, 6 | } from "@effectai/sdk"; 7 | 8 | // Create client and connect session 9 | const client = await createClient({ network }); 10 | 11 | const actor = "forcedev1234"; 12 | // Retrieve the vAccounts 13 | const [vacc] = await getVAccounts({ client, actor }); 14 | console.log(vacc); 15 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/get-pending-payments.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createClient, 3 | jungle4 as network, 4 | // eos as network, 5 | getVAccounts, 6 | getPendingPayments, 7 | } from "@effectai/sdk"; 8 | 9 | // Create client and connect session 10 | const client = await createClient({ network }); 11 | 12 | const actor = "forcedev1234"; 13 | // Retrieve the vAccounts 14 | const [vacc] = await getVAccounts({ client, actor }); 15 | 16 | const pendingPayments = await getPendingPayments({ 17 | client, 18 | vAccountId: vacc.id, 19 | }); 20 | 21 | console.log(pendingPayments); 22 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/payout.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | jungle4 as chain, 5 | // eos as chain, 6 | Session, 7 | payout, 8 | type PayoutArgs, 9 | getPendingPayments, 10 | getVAccounts, 11 | } from "@effectai/sdk"; 12 | 13 | const actor = "actor-name"; 14 | const permission = "permission-level"; 15 | 16 | // Create a session 17 | const session = new Session({ 18 | chain, 19 | actor, 20 | permission, 21 | walletPlugin: new WalletPluginPrivateKey("your_private_key"), 22 | }); 23 | 24 | // Create client and connect session 25 | const client = await createClient({ session }); 26 | 27 | const [vacc] = await getVAccounts({ client, actor }); 28 | 29 | // Check pending payments, 30 | // Not nessesary for this snippet, but helpful to know if there are any pending payments. 31 | // This check is also already done in the payout function. 32 | const pendingPayments = await getPendingPayments({ 33 | client, 34 | vAccountId: vacc.id, 35 | }); 36 | 37 | // If there are claimable payments, claim and pay them out. 38 | const result = await payout({ client, actor }); 39 | -------------------------------------------------------------------------------- /docs/snippets/vaccount/withdraw.ts: -------------------------------------------------------------------------------- 1 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 2 | import { 3 | createClient, 4 | jungle4 as chain, 5 | // eos as chain, 6 | Session, 7 | withdraw, 8 | type WithdrawArgs, 9 | getVAccounts, 10 | } from "@effectai/sdk"; 11 | 12 | const actor = "actor-name"; 13 | const permission = "permission-level"; 14 | 15 | // Create a session 16 | const session = new Session({ 17 | chain, 18 | actor, 19 | permission, 20 | walletPlugin: new WalletPluginPrivateKey("your_private_key"), 21 | }); 22 | 23 | // Create client and connect session 24 | const client = await createClient({ session }); 25 | 26 | // Retrieve user balance 27 | const [vacc] = await getVAccounts({ client, actor }); 28 | console.log(vacc.balance); 29 | 30 | // If there are claimable payments, claim and pay them out. 31 | const result = await withdraw({ client, quantity: 42 }); 32 | -------------------------------------------------------------------------------- /docs/styles.css: -------------------------------------------------------------------------------- 1 | @layer vocs_preflight { 2 | @tailwind base; 3 | } 4 | 5 | @tailwind components; 6 | @tailwind utilities; 7 | 8 | #home-install .vocs_CodeGroup { 9 | display: flex; 10 | height: 100%; 11 | flex-direction: column; 12 | } 13 | 14 | #home-install .vocs_Tabs_content { 15 | flex: 1; 16 | } 17 | 18 | #home-install .vocs_Code { 19 | font-size: 18px; 20 | } -------------------------------------------------------------------------------- /docs/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./pages/**/*.{js,ts,jsx,tsx,md,mdx}", "./pages/index.mdx"], 4 | darkMode: "class", 5 | important: true, 6 | theme: { 7 | extend: {}, 8 | }, 9 | plugins: [], 10 | }; 11 | -------------------------------------------------------------------------------- /docs/vocs.config.tsx: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vocs"; 2 | import pkg from "../src/package.json"; 3 | import { sidebar } from "./sidebar"; 4 | 5 | export default defineConfig({ 6 | baseUrl: "https://docs.effect.ai", 7 | title: "Effect SDK Docs", 8 | titleTemplate: "%s · Effect.AI", 9 | description: 10 | "Effect-js is a free and open-source library powered by blockchain technology that enables developers to collect and enrich their data-sets in a transparent way.", 11 | ogImageUrl: { 12 | "/": "/og-image.png", 13 | }, 14 | iconUrl: { light: "/favicons/light.png", dark: "/favicons/dark.png" }, 15 | logoUrl: { light: "/effect-logo-black.png", dark: "/effect-logo-black.png" }, 16 | rootDir: ".", 17 | sidebar, 18 | socials: [ 19 | { 20 | icon: "github", 21 | link: "https://github.com/effectai", 22 | }, 23 | { 24 | icon: "discord", 25 | link: "https://discord.gg/effectnetwork", 26 | }, 27 | { 28 | icon: "x", 29 | link: "https://x.com/effectaix", 30 | }, 31 | ], 32 | theme: { 33 | accentColor: { 34 | light: "#333", 35 | dark: "#ffc517", 36 | }, 37 | }, 38 | topNav: [ 39 | { text: "Docs", link: "/docs/getting-started", match: "/docs" }, 40 | { 41 | text: "Examples", 42 | link: "https://github.com/effectai/effect-js/tree/main/examples", 43 | }, 44 | { 45 | text: pkg.version, 46 | items: [ 47 | { 48 | text: `Migrating to ${toPatchVersionRange(pkg.version)}`, 49 | link: `/docs/migration-guide#_${toPatchVersionRange( 50 | pkg.version, 51 | ).replace(/\./g, "-")}-breaking-changes`, 52 | }, 53 | { 54 | text: "Changelog", 55 | link: "https://github.com/effectai/effect-js/blob/main/CHANGELOG.MD", 56 | }, 57 | { 58 | text: "Contributing", 59 | link: "https://github.com/effectai/effect-js/blob/main/CONTRIBUTING.MD", 60 | }, 61 | ], 62 | }, 63 | ], 64 | }); 65 | 66 | function toPatchVersionRange(version: string) { 67 | const [major, minor] = version.split(".").slice(0, 2); 68 | return `${major}.${minor}.x`; 69 | } 70 | -------------------------------------------------------------------------------- /environments/node/.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | -------------------------------------------------------------------------------- /environments/node/README.md: -------------------------------------------------------------------------------- 1 | # node 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.7. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. 16 | -------------------------------------------------------------------------------- /environments/node/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/environments/node/bun.lockb -------------------------------------------------------------------------------- /environments/node/index.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello via Bun!"); 2 | -------------------------------------------------------------------------------- /environments/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node", 3 | "module": "index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /environments/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | // Some stricter flags (disabled by default) 23 | "noUnusedLocals": false, 24 | "noUnusedParameters": false, 25 | "noPropertyAccessFromIndexSignature": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /environments/vite/.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | -------------------------------------------------------------------------------- /environments/vite/README.md: -------------------------------------------------------------------------------- 1 | # vite 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.7. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. 16 | -------------------------------------------------------------------------------- /environments/vite/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/environments/vite/bun.lockb -------------------------------------------------------------------------------- /environments/vite/index.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello via Bun!"); 2 | -------------------------------------------------------------------------------- /environments/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite", 3 | "module": "index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /environments/vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | // Some stricter flags (disabled by default) 23 | "noUnusedLocals": false, 24 | "noUnusedParameters": false, 25 | "noPropertyAccessFromIndexSignature": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Welcome to the Examples Directory! 2 | 3 | This directory is constantly evolving and open to contributions from everyone. 4 | 5 | Each example should come with its own dedicated StackBlitz project, making it easy for users to experiment with the examples. 6 | 7 | The list below is not exhaustive and is continuously expanding. If you have an idea for an example that isn’t listed, please start a discussion thread to propose it. If you’d like to work on an example that hasn’t been completed yet, feel free to dive in! -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@effectai/sdk", 3 | "workspaces": ["docs", "src"], 4 | "scripts": { 5 | "test": "bun --env-file=.env test", 6 | "test:watch": "bun --env-file=.env test --watch", 7 | "test:only": "bun --env-file=.env test --watch --only", 8 | "test:coverage": "bun --env-file=.env test --coverage", 9 | "dev": "tsc -w --project src/tsconfig.build.json", 10 | "build": "bun run sdk:build && bun run docs:build", 11 | "lint": "biome lint --apply .", 12 | "format": "biome format --write .", 13 | "check": "biome check --apply .", 14 | "changeset": "changeset", 15 | "changeset:public": "bun scripts/updateVersion.ts && bun run build && changeset publish", 16 | "changeset:version": "changeset version && bun install --frozen-lockfile && bun scripts/updateVersion.ts", 17 | "changeset:publish": "bun run build && changeset publish", 18 | "docs:dev": "cd docs && bun run dev", 19 | "docs:build": "cd docs && bun run build", 20 | "docs:preview": "cd docs && bun run preview", 21 | "sdk:build": "tsc --project src/tsconfig.build.json --module es2020", 22 | "link": "cd src && bun link" 23 | }, 24 | "devDependencies": { 25 | "@biomejs/biome": "1.7.0", 26 | "@wharfkit/wallet-plugin-privatekey": "^1.0.0", 27 | "@changesets/changelog-github": "^0.4.5", 28 | "@changesets/cli": "^2.23.2", 29 | "@greymass/abi2core": "^2.0.1", 30 | "@size-limit/preset-big-lib": "^11.1.2", 31 | "@types/bun": "^1.1.1", 32 | "typescript": "5.4.2", 33 | "vite": "^5.0.7" 34 | }, 35 | "trustedDependencies": ["@biomejs/biome"], 36 | "dependencies": { 37 | "@wharfkit/transact-plugin-autocorrect": "^1.2.1", 38 | "gh-pages": "^6.1.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/generateAbiTypes.ts: -------------------------------------------------------------------------------- 1 | import { transform } from "@greymass/abi2core"; 2 | import type { ABI } from "@wharfkit/antelope"; 3 | 4 | const getAbi = async (name: string) => { 5 | const abis = await fetch("https://eos.greymass.com/v1/chain/get_abi", { 6 | method: "POST", 7 | body: JSON.stringify({ account_name: name }), 8 | }); 9 | const data = await abis.json(); 10 | return data; 11 | }; 12 | 13 | const getPrimitive = (field: any) => { 14 | switch (field) { 15 | case "string": 16 | return "string"; 17 | case "bool": 18 | return "boolean"; 19 | case "uint8": 20 | return "number"; 21 | case "uint32": 22 | return "number"; 23 | case "uint64": 24 | return "number"; 25 | case "address": 26 | return "string"; 27 | case "bytes": 28 | return "string"; 29 | case "extended_asset": 30 | return "{quantity: string, contract: string}"; 31 | case "checksum160": 32 | return "string"; 33 | case "checksum256": 34 | return "string"; 35 | case "name": 36 | return "string"; 37 | case "time_point_sec": 38 | return "string"; 39 | case "float32": 40 | return "number"; 41 | default: 42 | return snakeToPascal(field); 43 | } 44 | }; 45 | 46 | const generateTypes = (abi: ABI) => { 47 | const types = abi.types.map((type) => { 48 | return `export type ${snakeToPascal(type.new_type_name)} = ${snakeToPascal( 49 | type.type, 50 | )};`; 51 | }); 52 | 53 | return types.join("\n"); 54 | }; 55 | 56 | const generateSchemaTypes = (abi: ABI) => { 57 | const types = abi.structs.map((struct) => { 58 | const fields = struct.fields.map((field) => { 59 | const isOptional = field.type.includes("?"); 60 | 61 | return `${field.name}${isOptional ? "?" : ""}: ${getPrimitive( 62 | field.type.replace("?", ""), 63 | )};`; 64 | }); 65 | 66 | return `export type ${snakeToPascal(struct.name)} = { ${fields.join( 67 | " ", 68 | )} };`; 69 | }); 70 | 71 | return types.join("\n"); 72 | }; 73 | 74 | const generateVariantTypes = (abi: ABI) => { 75 | const types = abi.variants.map((variant) => { 76 | const fields = variant.types.map((field) => { 77 | return getPrimitive(field); 78 | }); 79 | 80 | return `export type ${snakeToPascal(variant.name)} = [ ${fields.join( 81 | ", ", 82 | )} ];`; 83 | }); 84 | 85 | return types.join("\n"); 86 | }; 87 | 88 | function snakeToPascal(name: string): string { 89 | return name 90 | .split("_") 91 | .map((v) => (v[0] ? v[0].toUpperCase() : "_") + v.slice(1)) 92 | .join(""); 93 | } 94 | 95 | const abis = ["tasks.efx", "vaccount.efx"]; 96 | 97 | const main = async () => { 98 | for (const abi of abis) { 99 | const abiData = await getAbi(abi); 100 | 101 | const types = generateTypes(abiData.abi); 102 | const variants = generateVariantTypes(abiData.abi); 103 | const schema = generateSchemaTypes(abiData.abi); 104 | 105 | console.log("writing to file", `src/@generated/types/${abi}.ts`); 106 | 107 | await Bun.write( 108 | `src/@generated/types/${abi}.ts`, 109 | `import type { BytesType, Checksum160Type, UInt64 } from "@wharfkit/antelope"; 110 | \n\n 111 | ${types}\n\n${variants}\n\n${schema}`, 112 | ); 113 | } 114 | }; 115 | 116 | main(); 117 | -------------------------------------------------------------------------------- /scripts/updateVersion.ts: -------------------------------------------------------------------------------- 1 | import { join } from "node:path"; 2 | 3 | // Writes the current package.json version to `./src/exports/version.ts`. 4 | const versionFilePath = join(import.meta.dir, "../src/exports/version.ts"); 5 | const packageJsonPath = join(import.meta.dir, "../src/package.json"); 6 | const packageVersion = (await Bun.file(packageJsonPath).json()).version; 7 | 8 | Bun.write(versionFilePath, `export const version = '${packageVersion}'\n`); 9 | -------------------------------------------------------------------------------- /src/@generated/types/vaccount.efx.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | BytesType, 3 | Checksum160, 4 | Checksum160Type, 5 | Signature, 6 | UInt64, 7 | } from "@wharfkit/antelope"; 8 | 9 | export type Address = Checksum160; 10 | export type Vaddress = VariantAddressName; 11 | 12 | export type VariantAddressName = [string, string]; 13 | 14 | export type Account = { 15 | id: number; 16 | nonce: number; 17 | address: Vaddress; 18 | balance: { quantity: string; contract: string }; 19 | }; 20 | export type ExtendedSymbol = { sym: symbol; contract: string }; 21 | export type Open = { acc: Vaddress; symbol: ExtendedSymbol; payer: string }; 22 | export type Vtransfer = { 23 | from_id: number; 24 | to_id: number; 25 | quantity: { quantity: string; contract: string }; 26 | memo: string; 27 | sig?: Signature; 28 | fee?: { quantity: string; contract: string }; 29 | }; 30 | export type Withdraw = { 31 | from_id: number; 32 | to_account: string; 33 | quantity: { quantity: string; contract: string }; 34 | memo: string; 35 | sig?: Signature; 36 | fee?: { quantity: string; contract: string }; 37 | }; 38 | -------------------------------------------------------------------------------- /src/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @effectai/sdk 2 | 3 | ## 2.0.2 4 | 5 | ### Patch Changes 6 | 7 | - 68b5d21: Change types to match contracts on mainnet instead of jungle 8 | fix getTaskData index to consider the current batch 9 | 10 | ## 2.0.1 11 | 12 | ### Patch Changes 13 | 14 | - d656216: - add symlinks for license and README 15 | - fix createBatch types 16 | - make createClient async 17 | - 8382b39: update getBalance action to return eos, efx and usdt balance. 18 | -------------------------------------------------------------------------------- /src/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Effect Network 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # 🔥 The @effectai/sdk Monorepo 2 | 3 |

4 | 5 | The @effectai/sdk is a free and open source library for training next-gen transparent AI models. Integrate the SDK into your app and tap into a global, decentralized workforce powered by blockchain technology. 6 | 7 | ## 🗒️ Documentation 8 | For full documentation, visit https://docs.effect.ai 9 | 10 | ## 🙋 Contributing 11 | If you want to add contributions to this repository, please follow the instructions in [contributing.md](CONTRIBUTING.md). 12 | 13 | ## 🏠 Local Development 14 | Follow the docs to Set Up Your Local Development Environment to contribute to the framework and documentation. 15 | 16 | ### Testing 17 | 18 | #### `.env` 19 | 20 | To run the tests locally, you will need to provide an EOS account that can be used to make transactions on your behalf. 21 | Copy the `.env.example` file to `.env.testnet` and fill in the required parameters. 22 | 23 | #### PowerUp 24 | 25 | You might need to power up your account, either by adding some Native Token to your account or EFX tokens. 26 | You can powerup your account at the following link: https://monitor4.jungletestnet.io/ 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/actions/atomic/getAccountAssets.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, describe } from "bun:test"; 2 | import { getAccountAssets, type IAssetRow } from "./getAccountAssets"; 3 | import { Name } from "@wharfkit/antelope"; 4 | import { createClient, eos } from "../../exports"; 5 | 6 | describe("getAccountAssets", async () => { 7 | const accountAssetExample: IAssetRow = { 8 | asset_id: "2199024546793", 9 | collection_name: "pomelo", 10 | schema_name: "astronauts", 11 | template_id: 7022, 12 | ram_payer: "pomelo", 13 | backed_tokens: [], 14 | immutable_serialized_data: [ 15 | 5, 46, 81, 109, 90, 57, 102, 105, 106, 75, 54, 100, 109, 113, 66, 121, 66, 16 | 81, 117, 105, 57, 66, 71, 74, 111, 68, 77, 83, 122, 84, 76, 90, 104, 70, 17 | 55, 69, 70, 53, 90, 88, 78, 112, 57, 67, 111, 78, 102, 71, 9, 6, 67, 121, 18 | 98, 111, 114, 103, 10, 8, 65, 113, 117, 97, 114, 105, 117, 109, 11, 5, 67, 19 | 108, 111, 119, 110, 12, 6, 77, 111, 100, 101, 114, 110, 13, 4, 78, 111, 20 | 110, 101, 14, 4, 66, 97, 108, 100, 15, 4, 78, 111, 110, 101, 16, 16, 68, 21 | 97, 114, 107, 32, 66, 114, 97, 115, 115, 32, 83, 116, 117, 100, 115, 17, 22 | 11, 70, 108, 111, 119, 101, 114, 32, 69, 121, 101, 115, 18, 6, 78, 111, 23 | 114, 109, 97, 108, 19, 4, 78, 111, 110, 101, 20, 4, 78, 111, 110, 101, 24 | ], 25 | mutable_serialized_data: [], 26 | }; 27 | 28 | test("getAccountAssets() returns IAssetRow", async () => { 29 | // const account = Name.from("cryptonode42"); 30 | // const client = createClient({ network: eos }); 31 | // const assets = await getAccountAssets({ client, account }); 32 | // expect(assets).toBeDefined(); 33 | // expect(assets).toBeArray(); 34 | // expect(assets[0]).toMatchObject(accountAssetExample); 35 | }); 36 | 37 | test("getAccountAssets() should throw return empty array when no assets are found", async () => { 38 | // const account = Name.from("cryptonode99"); 39 | // const client = await createClient({ network: eos }); 40 | // const assets = await getAccountAssets({ client, account }); 41 | // expect(assets).toBeDefined(); 42 | // expect(assets).toBeArray(); 43 | // expect(assets).toBeEmpty(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/actions/atomic/getAccountAssets.ts: -------------------------------------------------------------------------------- 1 | import type { NameType, UInt32 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import type { GetTableRowsResponse } from "../../exports"; 4 | 5 | export type getAccountAssetsArgs = { 6 | client: Client; 7 | account: NameType; 8 | }; 9 | 10 | // TODO: What does this comment mean? 11 | // Override this interface, atomicassets exports a broken type. 12 | export interface IAssetRow { 13 | asset_id: string; 14 | collection_name: string; 15 | schema_name: string; 16 | template_id: number; 17 | ram_payer: string; 18 | backed_tokens: string[]; 19 | immutable_serialized_data: number[]; 20 | mutable_serialized_data: number[]; 21 | } 22 | 23 | // TODO:: Implement Pagination 24 | export const getAccountAssets = async ({ 25 | client, 26 | account, 27 | }: getAccountAssetsArgs) => { 28 | const { atomic } = client.network.config; 29 | const { provider } = client; 30 | 31 | const { rows } = (await provider.v1.chain.get_table_rows({ 32 | code: atomic.atomicContract, 33 | scope: account, 34 | table: "assets", 35 | limit: 100, 36 | })) as GetTableRowsResponse; 37 | 38 | return rows; 39 | }; 40 | -------------------------------------------------------------------------------- /src/actions/atomic/getAsset.ts: -------------------------------------------------------------------------------- 1 | import { UInt128 } from "@wharfkit/antelope"; 2 | import { ObjectSchema, deserialize } from "atomicassets"; 3 | import type { 4 | IAssetRow, 5 | ISchemaRow, 6 | } from "atomicassets/build/API/Rpc/RpcCache"; 7 | import type { Client } from "../../client"; 8 | import { getSchema } from "./getSchema"; 9 | 10 | export const deserializeAsset = (asset: IAssetRow, schema: ISchemaRow) => { 11 | const objectSchema = ObjectSchema(schema.format); 12 | const mutable_deserialized_data = deserialize( 13 | asset.mutable_serialized_data, 14 | objectSchema, 15 | ); 16 | 17 | const immutable_deserialized_data = deserialize( 18 | asset.immutable_serialized_data, 19 | objectSchema, 20 | ); 21 | 22 | return { 23 | ...asset, 24 | immutable_deserialized_data, 25 | mutable_deserialized_data, 26 | }; 27 | }; 28 | 29 | export type getAssetArgs = { 30 | client: Client; 31 | account: string; 32 | assetId: string; 33 | doDeserializeAsset?: boolean; 34 | }; 35 | 36 | export const getAsset = async ({ 37 | client, 38 | account, 39 | assetId, 40 | doDeserializeAsset = true, 41 | }: getAssetArgs) => { 42 | try { 43 | const { provider } = client; 44 | const { atomicContract } = client.network.config.atomic; 45 | 46 | const { rows } = await provider.v1.chain.get_table_rows({ 47 | code: atomicContract, 48 | scope: account, 49 | table: "assets", 50 | limit: 1, 51 | lower_bound: UInt128.from(assetId), 52 | upper_bound: UInt128.from(assetId), 53 | }); 54 | 55 | const [asset] = rows; 56 | 57 | if (doDeserializeAsset) { 58 | const schema = await getSchema({ 59 | client, 60 | collectionName: asset.collection_name, 61 | schemaName: asset.schema_name, 62 | }); 63 | 64 | return deserializeAsset(asset, schema); 65 | } 66 | return asset; 67 | } catch (error) { 68 | console.error(error); 69 | throw error; 70 | } 71 | }; 72 | -------------------------------------------------------------------------------- /src/actions/atomic/getCollection.ts: -------------------------------------------------------------------------------- 1 | import type { ICollectionRow } from "atomicassets/build/API/Rpc/RpcCache"; 2 | import type { Client } from "../../client"; 3 | import type { UInt32 } from "@wharfkit/antelope"; 4 | import type { GetTableRowsResponse } from "../../exports"; 5 | 6 | export type getCollectionArgs = { 7 | client: Client; 8 | collectionName: string; 9 | }; 10 | 11 | export const getCollection = async ({ 12 | client, 13 | collectionName, 14 | }: getCollectionArgs) => { 15 | const { atomic } = client.network.config; 16 | const { provider } = client; 17 | 18 | const { rows } = (await provider.v1.chain.get_table_rows({ 19 | code: atomic.atomicContract, 20 | scope: collectionName, 21 | table: "collections", 22 | limit: 100, 23 | })) as GetTableRowsResponse; 24 | 25 | return rows; 26 | }; 27 | -------------------------------------------------------------------------------- /src/actions/atomic/getSchema.ts: -------------------------------------------------------------------------------- 1 | import type { ISchemaRow } from "atomicassets/build/API/Rpc/RpcCache"; 2 | import type { Client } from "../../client"; 3 | 4 | export type getSchemaArgs = { 5 | client: Client; 6 | collectionName: string; 7 | schemaName: string; 8 | }; 9 | 10 | export const getSchema = async ({ 11 | client, 12 | collectionName, 13 | schemaName, 14 | }: getSchemaArgs): Promise => { 15 | const { atomic } = client.network.config; 16 | const { provider } = client; 17 | 18 | const { rows } = await provider.v1.chain.get_table_rows({ 19 | code: atomic.atomicContract, 20 | scope: collectionName, 21 | table: "schemas", 22 | limit: 100, 23 | }); 24 | 25 | const schema = rows.find( 26 | (schema: ISchemaRow) => schema.schema_name === schemaName, 27 | ); 28 | 29 | return schema; 30 | }; 31 | -------------------------------------------------------------------------------- /src/actions/dao/getAvatar.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../client"; 2 | import { useEFXContracts } from "../../utils/state"; 3 | 4 | export type GetAvatarArgs = { 5 | client: Client; 6 | account: string; 7 | }; 8 | 9 | // TODO: This does not seem to be working as expected 10 | export const getAvatar = async ({ client, account }: GetAvatarArgs) => { 11 | const { dao } = useEFXContracts(client); 12 | const { provider } = client; 13 | 14 | const response = await provider.v1.chain.get_table_rows({ 15 | code: dao, 16 | scope: account, 17 | table: "avatar", 18 | limit: 1, 19 | }); 20 | 21 | const [avatar] = response.rows; 22 | return avatar; 23 | }; 24 | -------------------------------------------------------------------------------- /src/actions/dao/getDaoSettings.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../client"; 2 | import { useEFXContracts } from "../../utils/state"; 3 | 4 | export type GetDaoSettingsArgs = { 5 | client: Client; 6 | }; 7 | 8 | export const getDaoSettings = async ({ client }: GetDaoSettingsArgs) => { 9 | const { dao } = useEFXContracts(client); 10 | const { provider } = client; 11 | 12 | const { rows } = await provider.v1.chain.get_table_rows({ 13 | code: dao, 14 | scope: dao, 15 | table: "config", 16 | limit: 1, 17 | }); 18 | 19 | const [config] = rows; 20 | return config; 21 | }; 22 | -------------------------------------------------------------------------------- /src/actions/dao/setAvatar.ts: -------------------------------------------------------------------------------- 1 | import type { IAssetRow } from "atomicassets/build/API/Rpc/RpcCache"; 2 | import type { Client } from "../../client"; 3 | import { SessionNotFoundError } from "../../errors"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | 6 | export type SetAvatarArgs = { 7 | client: Client; 8 | asset: IAssetRow; 9 | }; 10 | 11 | export const setAvatar = async ({ client, asset }: SetAvatarArgs) => { 12 | if (!client.session) { 13 | throw new SessionNotFoundError("Session is required for this method."); 14 | } 15 | 16 | const { actor, permission, transact } = client.session; 17 | const { dao } = useEFXContracts(client); 18 | 19 | const response = await transact({ 20 | actions: [ 21 | { 22 | account: dao, 23 | name: "setavatar", 24 | authorization: [ 25 | { 26 | actor, 27 | permission, 28 | }, 29 | ], 30 | data: { 31 | account: actor, 32 | asset_id: asset.asset_id, 33 | }, 34 | }, 35 | ], 36 | }); 37 | 38 | return response; 39 | }; 40 | -------------------------------------------------------------------------------- /src/actions/ipfs/getIpfsResource.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../client"; 2 | 3 | export enum IpfsContentFormat { 4 | FormData = "formdata", 5 | ArrayBuffer = "arraybuffer", 6 | Blob = "blob", 7 | Text = "text", 8 | JSON = "json", 9 | } 10 | 11 | export type CachedItem = { 12 | data: unknown; 13 | timestamp: number; 14 | }; 15 | 16 | export type GetIpfsResourceArgs = { 17 | client: Client; 18 | hash: string; 19 | ipfsContentForm?: IpfsContentFormat; 20 | }; 21 | 22 | export const getIpfsResource = async ({ 23 | client, 24 | hash, 25 | ipfsContentForm = IpfsContentFormat.JSON, 26 | }: GetIpfsResourceArgs) => { 27 | try { 28 | const { ipfs } = client.network.config; 29 | const { ipfsCacheDurationInMs } = client.options; 30 | const cache = client.cache; 31 | const cacheKey = `${hash}-${ipfsContentForm}`; 32 | 33 | if (ipfsCacheDurationInMs) { 34 | // Create a cache key 35 | const cacheKey = `${hash}-${ipfsContentForm}`; 36 | 37 | const cachedItem = (await cache.get(cacheKey)) as CachedItem | undefined; 38 | // If we have the response cached, return it 39 | if ( 40 | cachedItem && 41 | Date.now() < cachedItem.timestamp + ipfsCacheDurationInMs 42 | ) { 43 | return cachedItem.data; 44 | } 45 | } 46 | 47 | const data = await client.fetchProvider.fetch( 48 | `${ipfs.ipfsEndpoint}/ipfs/${hash}`, 49 | ); 50 | 51 | let result: string | Blob | ArrayBuffer | FormData | unknown; 52 | // Return the IPFS content in the format you want 53 | switch (ipfsContentForm) { 54 | case IpfsContentFormat.FormData: 55 | result = data.formData(); 56 | break; 57 | case IpfsContentFormat.ArrayBuffer: 58 | result = data.arrayBuffer(); 59 | break; 60 | case IpfsContentFormat.Blob: 61 | result = data.blob(); 62 | break; 63 | case IpfsContentFormat.Text: 64 | result = data.text(); 65 | break; 66 | case IpfsContentFormat.JSON: 67 | result = await data.json(); 68 | break; 69 | default: 70 | result = data; 71 | break; 72 | } 73 | 74 | // After we got the result, cache it 75 | if (ipfsCacheDurationInMs) { 76 | cache.set(cacheKey, { data: result, timestamp: Date.now() }); 77 | } 78 | 79 | return result; 80 | } catch (error) { 81 | console.error(error); 82 | } 83 | }; 84 | -------------------------------------------------------------------------------- /src/actions/ipfs/uploadIpfsResource.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../client"; 2 | import { Bytes, Base58 } from "@wharfkit/antelope"; 3 | 4 | export type UploadIpfsResourceArgs = { 5 | client: Client; 6 | data: Record | Record[]; 7 | }; 8 | 9 | export const uploadIpfsResource = async ({ 10 | client, 11 | data, 12 | }: UploadIpfsResourceArgs) => { 13 | try { 14 | const { ipfs } = client.network.config; 15 | 16 | const blob = new Blob([JSON.stringify(data)], { 17 | type: "application/json", 18 | }); 19 | 20 | const formData = new FormData(); 21 | formData.append("file", blob); 22 | 23 | if (blob.size > 1024 * 1024 * 10) { 24 | throw new Error("File too large, max file size is: 10MB"); 25 | } 26 | const requestOptions: RequestInit = { 27 | method: "POST", 28 | body: formData, 29 | }; 30 | 31 | const response = await client.fetchProvider.fetch( 32 | `${ipfs.ipfsEndpoint}/api/v0/add?pin=true`, 33 | requestOptions, 34 | ); 35 | 36 | if (!response.ok) { 37 | const errorText = await response.text(); 38 | throw new Error(`Error in IPFS upload: ${errorText}`); 39 | } 40 | const json = await response.json(); 41 | return json.Hash as string; 42 | } catch (error: unknown) { 43 | console.error("Error in IPFS upload", error); 44 | throw error; 45 | } 46 | }; 47 | 48 | export const ipfsCIDToHex = (cid: string): string => { 49 | return Base58.decode(cid).hexString; 50 | }; 51 | -------------------------------------------------------------------------------- /src/actions/session/createSession.ts: -------------------------------------------------------------------------------- 1 | import { Session } from "@wharfkit/session"; 2 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 3 | import type { Client } from "../../client"; 4 | import { setSession } from "./setSession"; 5 | 6 | export type CreateSessionArgs = { 7 | client: Client; 8 | actor: string; 9 | permission: string; 10 | privateKey: string; 11 | }; 12 | 13 | export const createSession = async ({ 14 | client, 15 | actor, 16 | permission, 17 | privateKey, 18 | }: CreateSessionArgs) => { 19 | const walletPlugin = new WalletPluginPrivateKey(privateKey); 20 | const { id, url } = client.network; 21 | 22 | const session = new Session({ 23 | actor, 24 | permission, 25 | walletPlugin, 26 | chain: { id, url }, 27 | }); 28 | 29 | await setSession({ client, session }); 30 | }; 31 | -------------------------------------------------------------------------------- /src/actions/session/setSession.ts: -------------------------------------------------------------------------------- 1 | import type { Session } from "@wharfkit/session"; 2 | import type { Client } from "../../client"; 3 | 4 | export type SetSessionArgs = { 5 | client: Client; 6 | session: Session | null; 7 | }; 8 | 9 | export const setSession = async ({ client, session }: SetSessionArgs) => { 10 | await client.setSession(session); 11 | }; 12 | -------------------------------------------------------------------------------- /src/actions/tasks/batch/createBatch.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../../test/src/utils"; 3 | import { 4 | createBatch, 5 | getBatchById, 6 | getCampaignById, 7 | getIpfsResource, 8 | } from "../../../exports"; 9 | 10 | describe("getAvatar", async () => { 11 | test.todo("Should create a new batch for given campaign", async () => { 12 | const campaignId = 1; 13 | const client = await testClientSession(); 14 | const preCampaign = await getCampaignById({ client, id: campaignId }); 15 | 16 | const batch = await getBatchById({ client, id: preCampaign.active_batch }); 17 | 18 | const batchData = await getIpfsResource({ 19 | client, 20 | hash: batch.content.field_1, 21 | }); 22 | 23 | const taskData: Record = { 24 | "e20bb19f-ca14-4575-8c14-1916896cb2f3": "Random question here", 25 | "35921e43-f058-4214-88e8-062a7eebe878": "Random answer here", 26 | "ba1865eb-6a52-4e06-9a64-ed351cf3f2e2": "Other question here", 27 | "b9d1a1f7-3b4f-4c7b-9b5d-3f0b3b7d4b9e": "Other answer here", 28 | }; 29 | 30 | const response = await createBatch({ 31 | client, 32 | campaignId, 33 | reward: 1, 34 | repetitions: 1, 35 | taskData, 36 | }); 37 | 38 | expect(response).toBeDefined(); 39 | 40 | const postCampaign = await getCampaignById({ client, id: campaignId }); 41 | expect(postCampaign.num_batches).toBeGreaterThan(preCampaign.num_batches); 42 | }); 43 | 44 | test.todo("Should fail when ...", async () => { 45 | // TODO: Should fail when there isn't enough funds, or session connected. 46 | // Figure out flow to test this 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/actions/tasks/batch/getBatch.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../../test/src/utils"; 3 | import { getBatchById, getCampaignById } from "../../../exports"; 4 | 5 | describe("getAvatar", async () => { 6 | test("Should create a new batch for given campaign", async () => { 7 | const campaignId = 1; 8 | const client = await testClientSession(); 9 | const campaign = await getCampaignById({ client, id: campaignId }); 10 | const batchById = await getBatchById({ 11 | client, 12 | id: campaign.active_batch, 13 | }); 14 | 15 | const batch = await getBatchById({ client, id: batchById.id }); 16 | expect(batch).toBeDefined(); 17 | expect(batch.id).toBe(batchById.id); 18 | }); 19 | 20 | test("Should return undefined if batch does not exist.", async () => { 21 | const nonExistentBatchId = 999999999; 22 | const client = await testClientSession(); 23 | const batch = await getBatchById({ client, id: nonExistentBatchId }); 24 | expect(batch).toBeUndefined(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/actions/tasks/batch/getBatch.ts: -------------------------------------------------------------------------------- 1 | import { UInt128 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../../client"; 3 | import { useEFXContracts } from "../../../utils/state"; 4 | import type { Batch, GetTableRowsResponse } from "../../../exports"; 5 | 6 | export type GetBatchByIdArgs = { 7 | client: Client; 8 | id: number; 9 | }; 10 | 11 | export const getBatchById = async ({ client, id }: GetBatchByIdArgs) => { 12 | const { provider } = client; 13 | const { tasks } = useEFXContracts(client); 14 | 15 | const response = (await provider.v1.chain.get_table_rows({ 16 | code: tasks, 17 | table: "batch", 18 | scope: tasks, 19 | lower_bound: UInt128.from(id), 20 | upper_bound: UInt128.from(id), 21 | limit: 1, 22 | })) as GetTableRowsResponse; 23 | 24 | const [batch] = response.rows; 25 | return batch; 26 | }; 27 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/createCampaign.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { createClient } from "../../../client"; 3 | import { type CreateCampaignArgs, createCampaign } from "./createCampaign"; 4 | import { testClientSession } from "../../../../test/src/utils"; 5 | import { jungle4 } from "../../../exports"; 6 | 7 | const myNewCampaign: CreateCampaignArgs["campaign"] = { 8 | version: 1.0, 9 | maxTaskTime: 100, 10 | reward: 3.5, 11 | title: "Labelstudio OCR (LAION)", 12 | description: 13 | "You are contributing to a dataset for conversational style chatbots.", 14 | instructions: "Some instructions here", 15 | template: "

Template here

", 16 | input_schema: null, 17 | output_schema: null, 18 | image: "", 19 | category: "", 20 | example_task: "", 21 | estimated_time: 10, 22 | }; 23 | 24 | describe("createCampaign", async () => { 25 | test("createCampaign() should throw an error", async () => { 26 | const client = await createClient({ network: jungle4 }); 27 | expect(async () => { 28 | await createCampaign({ 29 | client, 30 | campaign: myNewCampaign, 31 | }); 32 | }).toThrowError(); 33 | }); 34 | 35 | test.skip("createCampaign() should create a new campaign", async () => { 36 | const client = await testClientSession(); 37 | const result = await createCampaign({ client, campaign: myNewCampaign }); 38 | expect(result).toBeDefined(); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/createCampaign.ts: -------------------------------------------------------------------------------- 1 | import type { AnyAction } from "@wharfkit/antelope"; 2 | import type { Client } from "../../../client"; 3 | import { SessionNotFoundError } from "../../../errors"; 4 | import { useEFXContracts } from "../../../utils/state"; 5 | import { uploadIpfsResource } from "../../ipfs/uploadIpfsResource"; 6 | import type { CampaignInfo } from "./getCampaigns"; 7 | import type { Mkcampaign, Quali } from "../../../@generated/types/tasks.efx"; 8 | 9 | export type CreateCampaignActionArgs = { 10 | client: Client; 11 | campaign: Mkcampaign; 12 | }; 13 | 14 | export const createCampaignAction = ({ 15 | client, 16 | campaign, 17 | }: CreateCampaignActionArgs): AnyAction => { 18 | if (!client.session) { 19 | throw new SessionNotFoundError("Session is required for this method."); 20 | } 21 | 22 | const { actor } = client.session; 23 | const { tasks } = useEFXContracts(client); 24 | 25 | return { 26 | account: tasks, 27 | name: "mkcampaign", 28 | authorization: [ 29 | { 30 | actor, 31 | permission: "active", 32 | }, 33 | ], 34 | data: campaign, 35 | }; 36 | }; 37 | 38 | export type CreateCampaignArgs = { 39 | client: Client; 40 | campaign: CampaignInfo & { 41 | reward: number; 42 | maxTaskTime: number; 43 | qualifications?: Quali[]; 44 | }; 45 | }; 46 | 47 | export const createCampaign = async ({ 48 | client, 49 | campaign, 50 | }: CreateCampaignArgs) => { 51 | if (!client.session) { 52 | throw new SessionNotFoundError("Session is required for this method."); 53 | } 54 | 55 | const { transact } = client.session; 56 | const { token } = useEFXContracts(client); 57 | 58 | try { 59 | // Upload Campaign data to IPFS 60 | const hash = await uploadIpfsResource({ client, data: campaign }); 61 | 62 | const response = await transact({ 63 | action: createCampaignAction({ 64 | client, 65 | campaign: { 66 | max_task_time: campaign.maxTaskTime, 67 | reward: { 68 | quantity: `${campaign.reward.toFixed(4)} EFX`, // `1.0000 EFX` 69 | contract: token, 70 | }, 71 | payer: client.session.actor.toString(), 72 | content: { field_0: 0, field_1: hash }, 73 | qualis: campaign.qualifications ?? [], 74 | owner: ["name", client.session.actor.toString()], 75 | }, 76 | }), 77 | }); 78 | 79 | return response; 80 | } catch (error) { 81 | console.error(error); 82 | throw error; 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/getAllCampaigns.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { createClient } from "../../../client"; 3 | import { getAllCampaigns } from "./getAllCampaigns"; 4 | import { campaign } from "../../../../test/src/constants"; 5 | import { jungle4 } from "../../../exports"; 6 | 7 | describe("getAllCampaigns", async () => { 8 | test("getAllCampaigns() should retrieve all campaign", async () => { 9 | const client = await createClient({ network: jungle4 }); 10 | const campaigns = await getAllCampaigns({ client }); 11 | expect(campaigns).toBeDefined(); 12 | expect(campaigns).toBeArray(); 13 | expect(campaigns[0]).toContainKeys(Object.keys(campaign)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/getAllCampaigns.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../../client"; 2 | import { getCampaigns } from "./getCampaigns"; 3 | 4 | export type GetAllCampaignsArgs = { 5 | client: Client; 6 | }; 7 | 8 | export const getAllCampaigns = async ({ client }: GetAllCampaignsArgs) => { 9 | const campaigns = []; 10 | let page = 1; 11 | let hasMore = true; 12 | 13 | while (hasMore) { 14 | const { rows, more } = await getCampaigns({ client, page }); 15 | campaigns.push(...rows); 16 | hasMore = more; 17 | page++; 18 | } 19 | 20 | return campaigns; 21 | }; 22 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/getCampaignById.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { createClient } from "../../../client"; 3 | import { getCampaignById } from "./getCampaignById"; 4 | import { jungle4 } from "../../../exports"; 5 | import { campaign as exampleCampaign } from "../../../../test/src/constants"; 6 | 7 | describe("getCampaignById", async () => { 8 | test("getCampaignById() should throw an error when accessing unretrievable id", async () => { 9 | const client = await createClient({ network: jungle4 }); 10 | const id = 11111; 11 | expect(async () => { 12 | await getCampaignById({ client, id }); 13 | }).toThrowError(); 14 | }); 15 | 16 | test("getCampaignById() should retrieve campaign on testnet", async () => { 17 | const client = await createClient({ network: jungle4 }); 18 | const id = 1; 19 | const campaign = await getCampaignById({ client, id }); 20 | expect(campaign).toBeDefined(); 21 | expect(campaign).toBeObject(); 22 | expect(campaign).toContainKeys(Object.keys(exampleCampaign)); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/getCampaignById.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type CampaignWithInfo, 3 | getIpfsResource, 4 | type Client, 5 | } from "../../../exports"; 6 | import { UInt128, type UInt32Type } from "@wharfkit/antelope"; 7 | 8 | export type getCampaignByIdArgs = { 9 | client: Client; 10 | id: UInt32Type; 11 | }; 12 | 13 | export const getCampaignById = async ({ 14 | client, 15 | id, 16 | }: getCampaignByIdArgs): Promise => { 17 | const { contracts } = client.network.config.efx; 18 | 19 | const response = await client.provider.v1.chain.get_table_rows({ 20 | table: "campaign", 21 | code: contracts.tasks, 22 | scope: contracts.tasks, 23 | lower_bound: UInt128.from(id), 24 | upper_bound: UInt128.from(id), 25 | limit: 1, 26 | }); 27 | 28 | const [campaign] = response.rows; 29 | const { field_1: hash } = campaign.content; 30 | campaign.info = await getIpfsResource({ client, hash }); 31 | 32 | return campaign; 33 | }; 34 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/getCampaigns.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { testClientSession } from "../../../../test/src/utils"; 3 | import { getCampaigns } from "./getCampaigns"; 4 | 5 | describe("getCampaigns", async () => { 6 | test("getCampaigns() should return 3 campaigns", async () => { 7 | const client = await testClientSession(); 8 | const campaigns = await getCampaigns({ client, limit: 3 }); 9 | expect(campaigns).toBeDefined(); 10 | expect(campaigns.rows).toBeArray(); 11 | expect(campaigns.rows.length).toBe(3); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/actions/tasks/campaigns/getCampaigns.ts: -------------------------------------------------------------------------------- 1 | import { UInt128 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../../client"; 3 | import type { GetTableRowsResponse } from "../../../types/helpers"; 4 | import { getIpfsResource } from "../../ipfs/getIpfsResource"; 5 | import type { Campaign } from "../../../@generated/types/tasks.efx"; 6 | 7 | export type CampaignInfo = { 8 | category: string; 9 | description: string; 10 | estimated_time: number; 11 | example_task: string; 12 | image: string; 13 | instructions: string; 14 | input_schema: string | null; 15 | output_schema: string | null; 16 | template: string; 17 | title: string; 18 | version: number; 19 | }; 20 | 21 | export type CampaignWithInfo = Campaign & { 22 | info?: CampaignInfo; 23 | }; 24 | 25 | export type GetCampaignsArgs = { 26 | client: Client; 27 | page?: number; 28 | limit?: number; 29 | reverse?: boolean; 30 | ipfsFetch?: boolean; 31 | }; 32 | 33 | export const getCampaigns = async ({ 34 | client, 35 | page = 1, 36 | limit = 20, 37 | reverse = false, 38 | ipfsFetch = true, 39 | }: GetCampaignsArgs): Promise> => { 40 | const { contracts } = client.network.config.efx; 41 | const provider = client.provider; 42 | 43 | const rows = []; 44 | const lowerBound: UInt128 = UInt128.from((page - 1) * limit); 45 | 46 | const response = (await provider.v1.chain.get_table_rows({ 47 | key_type: "i128", 48 | code: contracts.tasks, 49 | table: "campaign", 50 | scope: contracts.tasks, 51 | lower_bound: lowerBound, 52 | limit, 53 | reverse, 54 | })) as GetTableRowsResponse; 55 | 56 | for (const row of response.rows) { 57 | const campaign: CampaignWithInfo = row; 58 | 59 | if (ipfsFetch) { 60 | campaign.info = (await getIpfsResource({ 61 | client, 62 | hash: campaign.content.field_1, 63 | })) as CampaignInfo; 64 | } 65 | 66 | rows.push(campaign); 67 | } 68 | 69 | return { 70 | rows, 71 | next_key: response.next_key, 72 | more: response.more, 73 | }; 74 | }; 75 | -------------------------------------------------------------------------------- /src/actions/tasks/getAccTaskIdx.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { destructureEnv, testClientSession } from "../../../test/src/utils"; 3 | import { getAccTaskIdx, getVAccounts } from "../../exports"; 4 | 5 | describe("getAccountTaskIndex", async () => { 6 | test("Should return an array", async () => { 7 | const client = await testClientSession(); 8 | const { actor } = destructureEnv(); 9 | const [vacc] = await getVAccounts({ client, actor }); 10 | 11 | const accTaskIdx = await getAccTaskIdx({ client, accountId: vacc.id }); 12 | expect(accTaskIdx).toBeDefined(); 13 | expect(accTaskIdx).toBeArray(); 14 | }); 15 | 16 | test.todo( 17 | "Should return a value within the array when reserving task", 18 | async () => { 19 | // TODO: Implement this test 20 | // Figure out flow of reserving a task, 21 | // retrieving the task index, 22 | // verifying the task index and 23 | // submitting the task to complete the cycle. 24 | }, 25 | ); 26 | }); 27 | -------------------------------------------------------------------------------- /src/actions/tasks/getAccTaskIdx.ts: -------------------------------------------------------------------------------- 1 | import { UInt32, type UInt64 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import { createCompositeU64Key } from "../../utils/keys"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | import type { Acctaskidx } from "../../@generated/types/tasks.efx"; 6 | import type { GetTableRowsResponse } from "../../exports"; 7 | 8 | export type GetAccTaskIdxArgs = { 9 | client: Client; 10 | accountId: number; 11 | campaignId?: number; 12 | }; 13 | 14 | export const getAccTaskIdx = async ({ 15 | client, 16 | accountId, 17 | campaignId, 18 | }: GetAccTaskIdxArgs) => { 19 | try { 20 | const { tasks } = useEFXContracts(client); 21 | const { provider } = client; 22 | 23 | const lowerBound = createCompositeU64Key(campaignId || 0, accountId); 24 | const upperBound = createCompositeU64Key( 25 | campaignId || Number(UInt32.max), 26 | accountId, 27 | ); 28 | 29 | const { rows } = (await provider.v1.chain.get_table_rows({ 30 | code: tasks, 31 | table: "acctaskidx", 32 | lower_bound: lowerBound, 33 | upper_bound: upperBound, 34 | })) as GetTableRowsResponse; 35 | 36 | return rows; 37 | } catch (error) { 38 | console.error(error); 39 | throw error; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /src/actions/tasks/getForceSettings.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../test/src/utils"; 3 | import { getForceSettings } from "../../exports"; 4 | 5 | describe("getForceSettings", async () => { 6 | const settingsExample = { 7 | vaccount_contract: "efxaccount11", 8 | force_vaccount_id: 11, 9 | payout_delay_sec: 1800, 10 | release_task_delay_sec: 1800, 11 | fee_contract: "efxfeepool11", 12 | fee_percentage: "0.10000000149011612", 13 | }; 14 | 15 | test("Should match config settings", async () => { 16 | const client = await testClientSession(); 17 | const settings = await getForceSettings({ client }); 18 | expect(settings).toBeDefined(); 19 | expect(Object.keys(settings)).toEqual(Object.keys(settingsExample)); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/actions/tasks/getForceSettings.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../client"; 2 | import type { GetTableRowsResponse } from "../../types/helpers"; 3 | import type { Settings } from "../../@generated/types/tasks.efx"; 4 | 5 | export type GetForceSettingsArgs = { 6 | client: Client; 7 | }; 8 | 9 | export const getForceSettings = async ({ client }: GetForceSettingsArgs) => { 10 | const { provider, network } = client; 11 | const { tasks } = network.config.efx.contracts; 12 | 13 | try { 14 | const response = (await provider.v1.chain.get_table_rows({ 15 | code: tasks, 16 | scope: tasks, 17 | table: "settings", 18 | })) as GetTableRowsResponse; 19 | 20 | const [config] = response.rows; 21 | return config; 22 | } catch (error) { 23 | console.error(error); 24 | throw new Error("Error retrieving Force settings"); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/actions/tasks/getRepetitions.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../test/src/utils"; 3 | import { getRepetitions } from "../../exports"; 4 | 5 | describe("getRepetitions", async () => { 6 | test("Should retrieve the repitions as array", async () => { 7 | const client = await testClientSession(); 8 | const repitions = await getRepetitions({ client }); 9 | expect(repitions).toBeDefined(); 10 | expect(repitions).toBeArray(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/actions/tasks/getRepetitions.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../client"; 2 | import { useEFXContracts } from "../../utils/state"; 3 | 4 | export type GetRepetitionsArgs = { 5 | client: Client; 6 | }; 7 | 8 | export const getRepetitions = async ({ client }: GetRepetitionsArgs) => { 9 | try { 10 | const { tasks } = useEFXContracts(client); 11 | const { provider } = client; 12 | 13 | const response = await provider.v1.chain.get_table_rows({ 14 | code: tasks, 15 | table: "repsdone", 16 | scope: tasks, 17 | }); 18 | 19 | return response.rows; 20 | } catch (error) { 21 | console.error(error); 22 | throw error; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/actions/tasks/getSubmissions.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../test/src/utils"; 3 | import { getSubmissions } from "../../exports"; 4 | 5 | describe("getSubmissions", async () => { 6 | const submissionExample = { 7 | id: 37, 8 | campaign_id: 6, 9 | task_idx: 0, 10 | account_id: 12, 11 | content: null, 12 | batch_id: "25769803776", 13 | data: { 14 | first: 1, 15 | second: 16 | "426624b24a7703d02c5797020c46dc10d573171c77b6eca915311ecb1820700c126f", 17 | }, 18 | paid: 0, 19 | submitted_on: "2024-05-04T20:39:30", 20 | }; 21 | 22 | test("Should get submissions", async () => { 23 | const client = await testClientSession(); 24 | const submissions = await getSubmissions({ client, reverse: false }); 25 | 26 | expect(submissions).toBeDefined(); 27 | expect(submissions).toBeArray(); 28 | 29 | const [submission] = submissions; 30 | expect(Object.keys(submission)).toEqual(Object.keys(submissionExample)); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/actions/tasks/getSubmissions.ts: -------------------------------------------------------------------------------- 1 | import type { UInt64Type } from "@wharfkit/antelope"; 2 | import type { Client } from "../../exports"; 3 | import type { GetTableRowsResponse } from "../../types/helpers"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | import type { Submission } from "../../@generated/types/tasks.efx"; 6 | 7 | export type GetSubmissionsArgs = { 8 | client: Client; 9 | reverse?: boolean; 10 | }; 11 | 12 | export const getSubmissions = async ({ 13 | client, 14 | reverse = false, 15 | }: GetSubmissionsArgs): Promise => { 16 | try { 17 | const { provider } = client; 18 | const { tasks } = useEFXContracts(client); 19 | 20 | const data = (await provider.v1.chain.get_table_rows({ 21 | code: tasks, 22 | table: "submission", 23 | json: true, 24 | reverse, 25 | })) as GetTableRowsResponse; 26 | 27 | const { rows } = data; 28 | 29 | return rows; 30 | } catch (e) { 31 | console.error("Error while fetching tasks:", e); 32 | throw new Error("Failed to fetch tasks"); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/actions/tasks/getTask.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../test/src/utils"; 3 | import { 4 | getAccTaskIdx, 5 | getBatchById, 6 | getCampaignById, 7 | getTaskData, 8 | } from "../../exports"; 9 | 10 | describe("getTask", async () => { 11 | test("Should get task", async () => { 12 | const client = await testClientSession(); 13 | const campaignById = await getCampaignById({ client, id: 1 }); 14 | const batchById = await getBatchById({ 15 | client, 16 | id: campaignById.active_batch, 17 | }); 18 | const taskIndex = batchById.start_task_idx; 19 | 20 | const taskData = await getTaskData({ 21 | client, 22 | taskIndex, 23 | batchId: batchById.id, 24 | }); 25 | expect(taskData).toBeDefined(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/actions/tasks/getTask.ts: -------------------------------------------------------------------------------- 1 | import type { UInt32Type } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | 4 | import { TaskIpfsError } from "../../errors"; 5 | import { getIpfsResource } from "../ipfs/getIpfsResource"; 6 | import { getBatchById } from "./batch/getBatch"; 7 | import type { Reservation } from "../../@generated/types/tasks.efx"; 8 | 9 | export type GetTaskDataArgs = { 10 | client: Client; 11 | taskIndex: number; 12 | batchId: number; 13 | }; 14 | 15 | export const getTaskData = async ({ 16 | client, 17 | taskIndex, 18 | batchId, 19 | }: GetTaskDataArgs) => { 20 | try { 21 | const batch = await getBatchById({ client, id: batchId }); 22 | 23 | const i = taskIndex - batch.start_task_idx; 24 | 25 | const ipfsData = await getIpfsResource({ 26 | client, 27 | hash: batch.content.field_1, 28 | }); 29 | 30 | // Check if the ipfsData is an array 31 | if (!Array.isArray(ipfsData)) { 32 | throw new TaskIpfsError( 33 | `Task data retrieved from IPFS is not an array. \n${String(ipfsData)}`, 34 | ); 35 | } 36 | 37 | // Check if there is a task at the index 38 | if (ipfsData.length <= i || i < 0) { 39 | throw new TaskIpfsError( 40 | `Task data retrieved from IPFS does not have a task at index ${taskIndex}. \n${JSON.stringify( 41 | ipfsData, 42 | )}`, 43 | ); 44 | } 45 | 46 | return ipfsData[i]; 47 | } catch (error: unknown) { 48 | console.error("Error while fetching task data:", error); 49 | throw error; 50 | } 51 | }; 52 | 53 | export const getTaskDataByReservation = ( 54 | client: Client, 55 | reservation: Reservation, 56 | ) => { 57 | return getTaskData({ 58 | client, 59 | taskIndex: reservation.task_idx, 60 | batchId: reservation.batch_idx, 61 | }); 62 | }; 63 | -------------------------------------------------------------------------------- /src/actions/tasks/reservations/getReservations.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { destructureEnv, testClientSession } from "../../../../test/src/utils"; 3 | import { 4 | getReservations, 5 | getReservationForCampaign, 6 | getReservationsForVAccount, 7 | getReservationsForCampaign, 8 | } from "./getReservations"; 9 | import { getVAccounts } from "../../vaccount/getAccounts"; 10 | 11 | describe("getReservation", async () => { 12 | test("Should return an array, with getReservations()", async () => { 13 | const client = await testClientSession(); 14 | const reservation = await getReservations({ client }); 15 | 16 | expect(reservation).toBeDefined(); 17 | expect(reservation).toBeArray(); 18 | }); 19 | 20 | test("Should get reservation for vAccount", async () => { 21 | const client = await testClientSession(); 22 | const { actor } = destructureEnv(); 23 | const [vacc] = await getVAccounts({ client, actor }); 24 | 25 | const reservation = await getReservationsForVAccount({ 26 | client, 27 | vAccountId: vacc.id, 28 | }); 29 | 30 | expect(reservation).toBeDefined(); 31 | expect(reservation).toBeArray(); 32 | }); 33 | 34 | test("Should get reservation for Campaigns", async () => { 35 | const client = await testClientSession(); 36 | const reservation = await getReservationsForCampaign({ 37 | client, 38 | campaignId: 1, 39 | }); 40 | 41 | expect(reservation).toBeDefined(); 42 | expect(reservation).toBeArray(); 43 | }); 44 | 45 | // TODO: Sometimes the user will not have a reservation, so we need to make sure that 46 | // a reservation is created before running this test. 47 | test.todo("Should get reservation for Campaign by vAccountId", async () => { 48 | const client = await testClientSession(); 49 | const { actor } = destructureEnv(); 50 | const [vacc] = await getVAccounts({ client, actor }); 51 | 52 | const reservation = await getReservationForCampaign({ 53 | client, 54 | vAccountId: vacc.id, 55 | campaignId: 1, 56 | }); 57 | 58 | expect(reservation).toBeDefined(); 59 | expect(reservation).toBeArray(); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/actions/tasks/reservations/getReservations.ts: -------------------------------------------------------------------------------- 1 | import { UInt32, UInt64 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../../client"; 3 | import type { GetTableRowsResponse } from "../../../types/helpers"; 4 | import { createCompositeU64Key } from "../../../utils/keys"; 5 | import { useEFXContracts } from "../../../utils/state"; 6 | import type { Reservation } from "../../../@generated/types/tasks.efx"; 7 | 8 | export type GetReservationsArgs = { 9 | client: Client; 10 | lowerBound?: UInt64; 11 | upperBound?: UInt64; 12 | indexPosition?: "secondary" | "fourth"; 13 | }; 14 | 15 | export const getReservations = async ({ 16 | client, 17 | lowerBound, 18 | upperBound, 19 | indexPosition = "secondary", 20 | }: GetReservationsArgs): Promise => { 21 | const { tasks } = useEFXContracts(client); 22 | 23 | const response = (await client.provider.v1.chain.get_table_rows({ 24 | scope: tasks, 25 | code: tasks, 26 | table: "reservation", 27 | index_position: indexPosition, 28 | upper_bound: upperBound, 29 | lower_bound: lowerBound, 30 | })) as GetTableRowsResponse; 31 | 32 | const { rows } = response; 33 | return rows; 34 | }; 35 | 36 | export type GetReservationsForCampaignArgs = { 37 | client: Client; 38 | campaignId: number; 39 | }; 40 | 41 | export const getReservationsForCampaign = async ({ 42 | client, 43 | campaignId, 44 | }: GetReservationsForCampaignArgs): Promise => { 45 | try { 46 | const lowerBound = createCompositeU64Key(campaignId, 0); 47 | const upperBound = createCompositeU64Key(campaignId, Number(UInt32.max)); 48 | return await getReservations({ client, lowerBound, upperBound }); 49 | } catch (e) { 50 | console.error(e); 51 | throw e; 52 | } 53 | }; 54 | 55 | export type GetReservationForVAccountArgs = { 56 | client: Client; 57 | vAccountId: number; 58 | }; 59 | 60 | export const getReservationsForVAccount = async ({ 61 | client, 62 | vAccountId, 63 | }: GetReservationForVAccountArgs): Promise => { 64 | try { 65 | if (!vAccountId) throw new Error("vAccountId is required"); 66 | 67 | return await getReservations({ 68 | client, 69 | lowerBound: UInt64.from(vAccountId), 70 | upperBound: UInt64.from(vAccountId), 71 | indexPosition: "fourth", 72 | }); 73 | } catch (e) { 74 | console.error(e); 75 | throw e; 76 | } 77 | }; 78 | 79 | export type GetReservationForCampaignArgs = { 80 | client: Client; 81 | campaignId: number; 82 | vAccountId: number; 83 | }; 84 | 85 | // TODO: This function name is unclear, we should rename it to: getVAccountReservationForCampaign 86 | export const getReservationForCampaign = async ({ 87 | client, 88 | campaignId, 89 | vAccountId, 90 | }: GetReservationForCampaignArgs): Promise => { 91 | try { 92 | const bound = createCompositeU64Key(campaignId, vAccountId); 93 | const data = await getReservations({ 94 | client, 95 | lowerBound: bound, 96 | upperBound: bound, 97 | }); 98 | 99 | const [reservation] = data; 100 | return reservation; 101 | } catch (e) { 102 | console.error(e); 103 | throw e; 104 | } 105 | }; 106 | -------------------------------------------------------------------------------- /src/actions/tasks/reservations/reserveTask.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../../test/src/utils"; 3 | import { reserveTask } from "./reserveTask"; 4 | 5 | describe("reserveTask", async () => { 6 | // TODO: Figure out flow for how to test this function 7 | test.todo("Should reserve task", async () => { 8 | const client = await testClientSession(); 9 | 10 | const reservation = await reserveTask({ client, campaignId: 1 }); 11 | 12 | expect(reservation).toBeDefined(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/actions/tasks/reservations/reserveTask.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from "../../../client"; 2 | import { useEFXContracts } from "../../../utils/state"; 3 | import { getReservationForCampaign } from "./getReservations"; 4 | 5 | export type ReserveTaskArgs = { 6 | client: Client; 7 | campaignId: number; 8 | qualificationAssets?: string[]; 9 | }; 10 | 11 | export const reserveTask = async ({ 12 | client, 13 | campaignId, 14 | qualificationAssets, 15 | }: ReserveTaskArgs) => { 16 | if (!client.session) { 17 | throw new Error("Session is required for this method."); 18 | } 19 | 20 | const { authorization, actor, transact } = client.session; 21 | const { tasks: taskContract } = useEFXContracts(client); 22 | const { vAccount } = client.session; 23 | 24 | if (!vAccount || !vAccount.id) { 25 | throw new Error("Vaccount is not set."); 26 | } 27 | 28 | // Check if the user already has a reservation for this campaign 29 | const existingReservation = await getReservationForCampaign({ 30 | client, 31 | campaignId, 32 | vAccountId: vAccount.id, 33 | }); 34 | 35 | // If there's already a reservation, return it 36 | if (existingReservation) { 37 | return existingReservation; 38 | } 39 | 40 | try { 41 | await transact({ 42 | action: { 43 | account: taskContract, 44 | name: "reservetask", 45 | authorization, 46 | data: { 47 | campaign_id: campaignId, 48 | account_id: vAccount.id, 49 | quali_assets: qualificationAssets, 50 | payer: actor, 51 | sig: null, 52 | }, 53 | }, 54 | }); 55 | 56 | return await getReservationForCampaign({ 57 | client, 58 | campaignId, 59 | vAccountId: vAccount.id, 60 | }); 61 | } catch (error) { 62 | console.error("Error while reserving task:", error); 63 | return null; 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /src/actions/tasks/submitTask.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { destructureEnv, testClientSession } from "../../../test/src/utils"; 3 | import { submitTask } from "./submitTask"; 4 | import { getReservationForCampaign } from "./reservations/getReservations"; 5 | import { getVAccounts } from "../vaccount/getAccounts"; 6 | 7 | describe("submitTask", async () => { 8 | // TODO: Figure out flow for how to test this function 9 | test.todo("Should submitTask", async () => { 10 | const client = await testClientSession(); 11 | const { actor } = destructureEnv(); 12 | const [vAccount] = await getVAccounts({ client, actor }); 13 | 14 | const reservation = await getReservationForCampaign({ 15 | client, 16 | campaignId: 1, 17 | vAccountId: vAccount.id, 18 | }); 19 | 20 | const response = await submitTask({ client, reservation, data: {} }); 21 | 22 | expect(response).toBeDefined(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/actions/tasks/submitTask.ts: -------------------------------------------------------------------------------- 1 | import { UInt32 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import { SessionNotFoundError } from "../../errors"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | import { uploadIpfsResource, ipfsCIDToHex } from "../ipfs/uploadIpfsResource"; 6 | import type { Reservation } from "../../@generated/types/tasks.efx"; 7 | 8 | export type SubmitTaskArgs = { 9 | client: Client; 10 | reservation: Reservation; 11 | data: Record; 12 | }; 13 | 14 | export const submitTask = async ({ 15 | client, 16 | reservation, 17 | data, 18 | }: SubmitTaskArgs) => { 19 | try { 20 | if (!client.session) { 21 | throw new SessionNotFoundError("Session is required for this method."); 22 | } 23 | 24 | const { authorization, transact, actor } = client.session; 25 | const { tasks } = useEFXContracts(client); 26 | 27 | const ipfsData = await uploadIpfsResource({ client, data }); 28 | const ipfsHex = ipfsCIDToHex(ipfsData); 29 | 30 | const response = await transact({ 31 | action: { 32 | account: tasks, 33 | name: "submittask", 34 | authorization, 35 | data: { 36 | campaign_id: UInt32.from(reservation.campaign_id), 37 | account_id: UInt32.from(reservation.account_id), 38 | task_idx: UInt32.from(reservation.task_idx), 39 | data: { first: 1, second: ipfsHex }, 40 | payer: actor, 41 | sig: null, 42 | }, 43 | }, 44 | }); 45 | return response; 46 | } catch (error) { 47 | console.error(error); 48 | throw error; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /src/actions/token/getBalance.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { getBalance } from "./getBalance"; 3 | import { createClient } from "../../client"; 4 | import { eos, jungle4 } from "../../exports"; 5 | 6 | describe("getBalance", async () => { 7 | test("getBalance() should retrieve balance from user on mainnet", async () => { 8 | const client = await createClient({ network: eos }); 9 | const actor = "cryptonode42"; 10 | const balance = await getBalance({ client, actor }); 11 | expect(balance).toBeDefined(); 12 | expect(balance.efxBalance).toBeDefined(); 13 | expect(balance.usdtBalance).toBeDefined(); 14 | expect(balance.eosBalance).toBeDefined(); 15 | expect(balance.efxBalance).toBeGreaterThan(0); 16 | expect(balance.usdtBalance).toBeGreaterThan(0); 17 | expect(balance.eosBalance).toBeGreaterThan(0); 18 | }); 19 | 20 | test("getBalance() should throw Error retrieving balance from unknown user.", async () => { 21 | const client = await createClient({ network: jungle4 }); 22 | const actor = "cryptonode99"; 23 | expect(async () => await getBalance({ client, actor })).toThrowError(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/actions/token/getBalance.ts: -------------------------------------------------------------------------------- 1 | import type { Asset, NameType } from "@wharfkit/session"; 2 | import type { Client } from "../../exports"; 3 | 4 | export type GetBalanceArgs = { 5 | client: Client; 6 | actor: NameType; 7 | }; 8 | 9 | export const getBalance = async ({ 10 | client, 11 | actor, 12 | }: GetBalanceArgs): Promise<{ 13 | efxBalance: Asset; 14 | usdtBalance: Asset; 15 | eosBalance: Asset; 16 | }> => { 17 | const { network, provider } = client; 18 | const { contracts } = network.config.efx; 19 | 20 | const [efxBalance] = await provider.v1.chain.get_currency_balance( 21 | contracts.token, 22 | actor, 23 | ); 24 | 25 | const [usdtBalance] = await provider.v1.chain.get_currency_balance( 26 | contracts.usdt, 27 | actor, 28 | ); 29 | 30 | const [eosBalance] = await provider.v1.chain.get_currency_balance( 31 | contracts.eostoken, 32 | actor, 33 | ); 34 | 35 | if (!efxBalance && !usdtBalance && !eosBalance) { 36 | throw new Error("No efxBalance found"); 37 | } 38 | 39 | return { 40 | efxBalance, 41 | usdtBalance, 42 | eosBalance, 43 | }; 44 | }; 45 | -------------------------------------------------------------------------------- /src/actions/token/getDefiBoxPair.test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/effectai/effect-js/40f3fea89f3b422e0176740379671de43de07162/src/actions/token/getDefiBoxPair.test.ts -------------------------------------------------------------------------------- /src/actions/token/getDefiBoxPair.ts: -------------------------------------------------------------------------------- 1 | export enum DefiBoxPairEnum { 2 | EosEfx = 191, 3 | EosUsdt = 12, 4 | } 5 | 6 | export const getDefiBoxPair = async (pairEnum: DefiBoxPairEnum) => { 7 | try { 8 | // TODO: Check how resilient this is, otherwise figure out how to use FetchProvider from the SDK Client. 9 | const useFetch = fetch ?? window.fetch; 10 | const result = await useFetch( 11 | "https://eos.greymass.com/v1/chain/get_table_rows", 12 | { 13 | method: "POST", 14 | body: JSON.stringify({ 15 | json: true, 16 | code: "swap.defi", 17 | scope: "swap.defi", 18 | table: "pairs", 19 | limit: 1, 20 | lower_bound: pairEnum.valueOf(), 21 | upper_bound: pairEnum.valueOf(), 22 | }), 23 | }, 24 | ); 25 | 26 | return result.json().then((data) => data.rows[0]); 27 | } catch (error) { 28 | console.error(error); 29 | throw new Error("Error retrieving EFX Ticker Price from DefiBox"); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/actions/token/getPrice.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { getPrice } from "./getPrice"; 3 | 4 | describe("getPrice", async () => { 5 | test("getPrice() should retrieve price on mainnet", async () => { 6 | const price = await getPrice(); 7 | expect(price).toBeDefined(); 8 | expect(price).toBeNumber(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/actions/token/getPrice.ts: -------------------------------------------------------------------------------- 1 | import { DefiBoxPairEnum, getDefiBoxPair } from "./getDefiBoxPair"; 2 | 3 | /** 4 | * Get the current price of EFX in USDT 5 | * @returns {Promis} The current price of EFX in USDT 6 | */ 7 | export const getPrice = async (): Promise => { 8 | try { 9 | const eosEfxPair = await getDefiBoxPair(DefiBoxPairEnum.EosEfx); 10 | const eosUsdtPair = await getDefiBoxPair(DefiBoxPairEnum.EosUsdt); 11 | const efxUsdt = 12 | Number(eosEfxPair.price1_last) * Number(eosUsdtPair.price0_last); 13 | return efxUsdt; 14 | } catch (error) { 15 | throw new Error("Error retrieving EFX Ticker Price from DefiBox"); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/actions/token/swap.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { createClient } from "../../client"; 3 | import { jungle4, swap } from "../../exports"; 4 | import type { SwapArgs } from "./swap"; 5 | import { testClientSession } from "../../../test/src/utils"; 6 | 7 | describe("buildSwapAction", async () => { 8 | test.todo("buildSwapAction() should return a swap action object."); 9 | }); 10 | 11 | describe("Swap", async () => { 12 | // Use Mainnet 13 | 14 | test("swap() should throw an error when Session is not set on Client.", async () => { 15 | const swapArgs: SwapArgs = { 16 | client: await createClient({ network: jungle4 }), 17 | amount: 1, 18 | direction: "UsdtToEfx", 19 | }; 20 | 21 | expect(async () => await swap(swapArgs)).toThrow( 22 | new Error("Error swapping: Error: Session is required for this method."), 23 | ); 24 | }); 25 | 26 | test("swap() should fail when amount is 0", async () => { 27 | const swapArgs: SwapArgs = { 28 | client: await testClientSession(), 29 | amount: 0, 30 | direction: "UsdtToEfx", 31 | }; 32 | 33 | expect(async () => await swap(swapArgs)).toThrow(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/actions/token/swap.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type AnyAction, 3 | Asset, 4 | type PermissionLevelType, 5 | type NameType, 6 | } from "@wharfkit/antelope"; 7 | import type { Client } from "../../client"; 8 | import { DefiBoxPairEnum } from "./getDefiBoxPair"; 9 | import { getPrice } from "./getPrice"; 10 | import { useEFXContracts } from "../../utils/state"; 11 | 12 | export const swapDirection = { 13 | EfxToUsdt: `${DefiBoxPairEnum.EosEfx}-${DefiBoxPairEnum.EosUsdt}`, 14 | UsdtToEfx: `${DefiBoxPairEnum.EosUsdt}-${DefiBoxPairEnum.EosEfx}`, 15 | }; 16 | 17 | export const buildSwapAction = ( 18 | direction: string, 19 | actor: NameType, 20 | authorization: PermissionLevelType[], 21 | amount: number, 22 | tokenContract: string, 23 | efxPrice: number, 24 | ) => { 25 | if (!authorization || !authorization.length || !actor) { 26 | throw new Error("No authorization provided"); 27 | } 28 | 29 | if (!amount || !efxPrice) { 30 | throw new Error("Amount or EFX price not provided"); 31 | } 32 | 33 | const valueAmount = efxPrice * amount; 34 | 35 | const swapAction: { 36 | [key: string]: AnyAction; 37 | } = { 38 | [swapDirection.EfxToUsdt]: { 39 | account: tokenContract, 40 | name: "transfer", 41 | authorization, 42 | data: { 43 | from: actor, 44 | to: "swap.defi", 45 | quantity: Asset.from(amount, "4,EFX"), 46 | memo: `swap,${valueAmount},${swapDirection.EfxToUsdt}`, 47 | }, 48 | }, 49 | [swapDirection.UsdtToEfx]: { 50 | account: "tethertether", 51 | name: "transfer", 52 | authorization, 53 | data: { 54 | from: actor, 55 | to: "swap.defi", 56 | quantity: Asset.from(amount, "4,USDT"), 57 | memo: `swap,${valueAmount},${swapDirection.UsdtToEfx}`, 58 | }, 59 | }, 60 | }; 61 | 62 | return swapAction[direction]; 63 | }; 64 | 65 | export type SwapArgs = { 66 | client: Client; 67 | amount: number; 68 | direction: "EfxToUsdt" | "UsdtToEfx"; 69 | }; 70 | 71 | // TODO: Add throw error if balance too low 72 | export const swap = async ({ client, amount, direction }: SwapArgs) => { 73 | try { 74 | if (!client.session) { 75 | throw new Error("Session is required for this method."); 76 | } 77 | 78 | const { transact, actor, authorization } = client.session; 79 | const { token: tokenContract } = useEFXContracts(client); 80 | const efxPrice = await getPrice(); 81 | 82 | const action = buildSwapAction( 83 | direction, 84 | actor, 85 | authorization, 86 | amount, 87 | tokenContract, 88 | efxPrice, 89 | ); 90 | 91 | if (!action) { 92 | throw new Error("Invalid swap action"); 93 | } 94 | 95 | return await transact({ action }); 96 | } catch (e) { 97 | throw new Error(`Error swapping: ${e}`); 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /src/actions/vaccount/claim.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../test/src/utils"; 3 | import { claim } from "../../exports"; 4 | 5 | describe("Claim", async () => { 6 | test.todo("Should throw when no payment is pending", async () => { 7 | const client = await testClientSession(); 8 | const response = await claim({ client }); 9 | // expect(async () => await claim({ client })).toThrow(); 10 | expect(response).toBeDefined(); 11 | }); 12 | 13 | test.todo("Should claim pending payments", async () => { 14 | // TODO: Should claim pending payments 15 | // Figure out flow to test this 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/actions/vaccount/claim.ts: -------------------------------------------------------------------------------- 1 | import type { AnyAction, NameType } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import { VAccountError } from "../../errors"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | import { getPendingPayments } from "./getPendingPayments"; 6 | import type { Payment } from "../../@generated/types/tasks.efx"; 7 | 8 | export type ClaimArgs = { 9 | client: Client; 10 | }; 11 | 12 | export const claim = async ({ client }: ClaimArgs) => { 13 | if (!client.session?.vAccount) { 14 | throw new VAccountError("vAccount is not set."); 15 | } 16 | 17 | const { tasks } = useEFXContracts(client); 18 | const { authorization } = client.session; 19 | 20 | const { claimablePayments } = await getPendingPayments({ 21 | client, 22 | vAccountId: client.session.vAccount.id, 23 | }); 24 | 25 | const actions = []; 26 | 27 | if (claimablePayments) { 28 | actions.push( 29 | ...claimActions({ 30 | payments: claimablePayments, 31 | tasks, 32 | authorization, 33 | }), 34 | ); 35 | } else { 36 | throw new Error("No pending payouts found"); 37 | } 38 | 39 | const { transact } = client.session; 40 | return await transact({ actions: actions }); 41 | }; 42 | 43 | export type ClaimActionsArgs = { 44 | payments: Payment[]; 45 | tasks: string; 46 | authorization: { actor: NameType; permission: NameType }[]; 47 | }; 48 | 49 | export const claimActions = ({ 50 | payments, 51 | tasks, 52 | authorization, 53 | }: ClaimActionsArgs): AnyAction[] => { 54 | const actions = []; 55 | 56 | for (const payment of payments) { 57 | actions.push({ 58 | account: tasks, 59 | name: "payout", 60 | authorization, 61 | data: { 62 | payment_id: payment.id, 63 | }, 64 | }); 65 | } 66 | 67 | return actions; 68 | }; 69 | -------------------------------------------------------------------------------- /src/actions/vaccount/createAccount.test.ts: -------------------------------------------------------------------------------- 1 | import { Name } from "@wharfkit/antelope"; 2 | 3 | import { expect, test, describe } from "bun:test"; 4 | 5 | import { createClient } from "../../client"; 6 | import { createVAccount } from "./createAccount"; 7 | 8 | import { jungle4 } from "../../exports"; 9 | import { testClientSession } from "../../../test/src/utils.js"; 10 | 11 | describe("Create Virtual account", () => { 12 | const network = jungle4; 13 | 14 | test.skip("createVAccount() should return a TransactResult", async () => { 15 | const client = await testClientSession(); 16 | const account = Name.from("efxforce1112"); 17 | const result = await createVAccount({ client, account }); 18 | expect(result).toBeDefined(); 19 | }); 20 | 21 | test("createVAccount() should throw Error when no Session is found", async () => { 22 | expect(async () => { 23 | const client = await createClient({ network: network }); 24 | const account = Name.from("efxforce1112"); 25 | await createVAccount({ client, account }); 26 | }).toThrowError(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/actions/vaccount/createAccount.ts: -------------------------------------------------------------------------------- 1 | import type { TransactResult, Session, NameType } from "@wharfkit/session"; 2 | import type { Client } from "../../client"; 3 | import { ExtendedSymbol } from "../../utils/structs"; 4 | import { VAddress } from "../../utils/variants"; 5 | 6 | export type CreateVAccountArgs = { 7 | client: Client; 8 | session?: Session; 9 | account?: NameType; 10 | }; 11 | 12 | export const createVAccount = async ({ 13 | client, 14 | session, 15 | account, 16 | }: CreateVAccountArgs): Promise => { 17 | const sessionToUse = session ?? client.session; 18 | 19 | if (!sessionToUse) { 20 | throw new Error("No session provided"); 21 | } 22 | 23 | // TODO: If no account is provided, use the current session actor. Not implemented yet 24 | const acc: NameType = account ?? sessionToUse.actor; 25 | 26 | const { actor } = sessionToUse; 27 | const { contracts, token } = client.network.config.efx; 28 | 29 | const authorization = [ 30 | { 31 | actor, 32 | permission: sessionToUse.permission, 33 | }, 34 | ]; 35 | 36 | const action = { 37 | account: contracts.vaccount, 38 | name: "open", 39 | authorization, 40 | data: { 41 | acc: VAddress.from(acc), 42 | symbol: new ExtendedSymbol( 43 | `${token.precision},${token.symbol}`, 44 | contracts.token, 45 | ), 46 | payer: actor, 47 | }, 48 | }; 49 | 50 | return await sessionToUse.transact({ action }); 51 | }; 52 | -------------------------------------------------------------------------------- /src/actions/vaccount/deposit.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { deposit } from "./deposit"; 3 | import { testClientSession, destructureEnv } from "../../../test/src/utils"; 4 | import { getVAccounts } from "./getAccounts"; 5 | 6 | describe("deposit", async () => { 7 | test.todo( 8 | "Should throw an error when Session is not set on Client.", 9 | () => {}, 10 | ); 11 | 12 | test.skip("Check that deposit is functioning correctly", async () => { 13 | const { actor } = destructureEnv(); 14 | const client = await testClientSession(); 15 | const [vAccount] = await getVAccounts({ client, actor }); 16 | const vAccountId = vAccount.id; 17 | const result = await deposit({ client, vAccountId, amount: 0.1 }); 18 | expect(result).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/actions/vaccount/deposit.ts: -------------------------------------------------------------------------------- 1 | import { type AnyAction, Asset } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import { SessionNotFoundError } from "../../errors"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | 6 | export type DepositActionArgs = { 7 | client: Client; 8 | amount: number; 9 | vAccountId: number; 10 | }; 11 | 12 | export const depositAction = ({ 13 | client, 14 | amount, 15 | vAccountId, 16 | }: DepositActionArgs): AnyAction => { 17 | if (!client.session) { 18 | throw new SessionNotFoundError("Session is required for this method."); 19 | } 20 | 21 | const { actor, authorization } = client.session; 22 | const { token, vaccount } = useEFXContracts(client); 23 | 24 | if (!vAccountId) { 25 | throw new Error("No vAccount ID provided."); 26 | } 27 | 28 | return { 29 | account: token, 30 | name: "transfer", 31 | authorization, 32 | data: { 33 | from: actor, 34 | to: vaccount, 35 | quantity: Asset.from(amount, "4,EFX"), 36 | memo: `${vAccountId}`, 37 | }, 38 | }; 39 | }; 40 | 41 | export type DepositArgs = { 42 | client: Client; 43 | vAccountId: number; 44 | amount: number; 45 | }; 46 | 47 | export const deposit = async ({ client, vAccountId, amount }: DepositArgs) => { 48 | try { 49 | if (!client.session) { 50 | throw new SessionNotFoundError("Session is required for this method."); 51 | } 52 | 53 | const { transact } = client.session; 54 | 55 | return await transact({ 56 | action: depositAction({ client, vAccountId, amount }), 57 | }); 58 | } catch (error) { 59 | console.error(error); 60 | throw new Error("Error depositing EFX"); 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /src/actions/vaccount/getAccounts.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe, beforeAll } from "bun:test"; 2 | import type { Client } from "../../client"; 3 | import { testClientSession } from "../../../test/src/utils"; 4 | import { getVAccounts, getAccountById } from "./getAccounts"; 5 | import type { Account } from "../../exports"; 6 | 7 | describe("Get Virtual Accounts", () => { 8 | const vaccExample: Account = { 9 | id: 0, 10 | nonce: 53, 11 | address: ["name", "efxforceacc1"], 12 | balance: { 13 | quantity: "3525.0000 EFX", 14 | contract: "effecttokens", 15 | }, 16 | }; 17 | 18 | let client: Client; 19 | beforeAll(async () => { 20 | client = await testClientSession(); 21 | }); 22 | 23 | test("getVAccounts() on testnet", async () => { 24 | const actor = "efxforce1112"; 25 | const vaccs = await getVAccounts({ client, actor }); 26 | expect(vaccs).toBeDefined(); 27 | expect(vaccs).toBeArray(); 28 | expect(vaccs[0]).toContainKeys(Object.keys(vaccExample)); 29 | }); 30 | 31 | test("getAccountById()", async () => { 32 | const vacc = await getAccountById({ client, accountId: 0 }); 33 | expect(vacc).toBeDefined(); 34 | expect(vacc).toContainKeys(Object.keys(vaccExample)); 35 | }); 36 | 37 | test("getAccountByID() should throw Error", async () => { 38 | const accountId = 9999999; // Should be imposible to find 39 | expect(async () => { 40 | await getAccountById({ client, accountId }); 41 | }).toThrowError(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/actions/vaccount/getAccounts.ts: -------------------------------------------------------------------------------- 1 | import { Name, type NameType, type UInt64Type } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import { NotFoundError } from "../../errors"; 4 | import { generateCheckSumForVAccount } from "../../utils/keys"; 5 | import type { Account } from "../../@generated/types/vaccount.efx"; 6 | 7 | export type GetVAccountsArgs = { 8 | client: Client; 9 | actor: NameType; 10 | }; 11 | 12 | export const getVAccounts = async ({ 13 | client, 14 | actor, 15 | }: GetVAccountsArgs): Promise => { 16 | const { provider, network } = client; 17 | const { contracts } = network.config.efx; 18 | 19 | const keycs = generateCheckSumForVAccount(Name.from(actor), contracts.token); 20 | 21 | const response = await provider.v1.chain.get_table_rows({ 22 | code: contracts.vaccount, 23 | table: "account", 24 | scope: contracts.vaccount, 25 | upper_bound: keycs, 26 | lower_bound: keycs, 27 | index_position: "secondary", 28 | key_type: "sha256", 29 | }); 30 | 31 | return response.rows; 32 | }; 33 | 34 | export type GetAccountByIdArgs = { 35 | client: Client; 36 | accountId: UInt64Type; 37 | }; 38 | 39 | export const getAccountById = async ({ 40 | client, 41 | accountId, 42 | }: GetAccountByIdArgs): Promise => { 43 | const { provider, network } = client; 44 | const { contracts } = network.config.efx; 45 | 46 | const response = await provider.v1.chain.get_table_rows({ 47 | code: contracts.vaccount, 48 | scope: contracts.vaccount, 49 | table: "account", 50 | limit: 1, 51 | key_type: "i64", 52 | upper_bound: accountId, 53 | lower_bound: accountId, 54 | }); 55 | 56 | const account = response.rows[0]; 57 | 58 | if (!account) { 59 | throw new NotFoundError(`Account with id ${accountId} not found`); 60 | } 61 | 62 | return account; 63 | }; 64 | -------------------------------------------------------------------------------- /src/actions/vaccount/getAvatar.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { createClient } from "../../client"; 3 | import { getAvatar, jungle4 as network } from "../../exports"; 4 | 5 | describe("getAvatar", async () => { 6 | test.todo("Should retrieve avatar for user", async () => { 7 | const client = await createClient({ network }); 8 | const account = "cryptonode42"; 9 | const response = await getAvatar({ client, account }); 10 | expect(response).toBeDefined(); 11 | }); 12 | 13 | test.todo("Should claim pending payments", async () => { 14 | // TODO: Should claim pending payments 15 | // Figure out flow to test this 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/actions/vaccount/getAvatar.ts: -------------------------------------------------------------------------------- 1 | import { getAsset } from "../atomic/getAsset"; 2 | import { 3 | getAvatar as getDaoAvatar, 4 | type GetAvatarArgs, 5 | } from "../dao/getAvatar"; 6 | 7 | // TODO: This function is failing, but it is not mission critical for the app to work. 8 | export const getAvatar = async ({ client, account }: GetAvatarArgs) => { 9 | const defaultImg = "QmZQiEWsaTNpANMv9orwDvuGyMRkY5nQNazSB1KkW4pM6t"; 10 | const defaultVid = "QmZQiEWsaTNpANMv9orwDvuGyMRkY5nQNazSB1KkW4pM6t"; 11 | 12 | // This function is failing, let's comment it out for now. 13 | // const daoAvatar = await getDaoAvatar({ client, account }); 14 | const asset = await getAsset({ 15 | client, 16 | account, 17 | assetId: "2199025109172", 18 | // assetId: daoAvatar.asset_id, 19 | }); 20 | return { 21 | ...asset, 22 | img: asset.immutable_deserialized_data?.img ?? defaultImg, 23 | video: asset.immutable_deserialized_data?.video ?? defaultVid, 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /src/actions/vaccount/getOrCreate.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { destructureEnv, testClientSession } from "../../../test/src/utils"; 3 | import type { Account } from "../../exports"; 4 | import { getOrCreateVAccount } from "./getOrCreate"; 5 | 6 | describe("GetOrCreate", async () => { 7 | const vaccExample: Account = { 8 | id: 0, 9 | nonce: 53, 10 | address: ["name", "efxforceacc1"], 11 | balance: { 12 | quantity: "3525.0000 EFX", 13 | contract: "effecttokens", 14 | }, 15 | }; 16 | 17 | test("Should get account", async () => { 18 | const client = await testClientSession(); 19 | const { actor } = destructureEnv(); 20 | const result = await getOrCreateVAccount({ client, actor }); 21 | expect(result).toBeDefined(); 22 | expect(result).toContainKeys(Object.keys(vaccExample)); 23 | }); 24 | 25 | test.todo("Should create new account", async () => { 26 | // TODO: Should create new account 27 | // Figure out flow to test this 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/actions/vaccount/getOrCreate.ts: -------------------------------------------------------------------------------- 1 | import type { NameType } from "@wharfkit/antelope"; 2 | import type { Session } from "@wharfkit/session"; 3 | import { 4 | type Client, 5 | createVAccount, 6 | getVAccounts, 7 | type Account, 8 | } from "../../exports"; 9 | 10 | export const getOrCreateVAccount = async ({ 11 | client, 12 | actor, 13 | session, 14 | }: { 15 | client: Client; 16 | actor: NameType; 17 | session?: Session; 18 | }): Promise => { 19 | try { 20 | let [account] = await getVAccounts({ client, actor }); 21 | 22 | if (!account) { 23 | await createVAccount({ client, session, account: actor }); 24 | 25 | [account] = await getVAccounts({ client, actor }); 26 | } 27 | 28 | return account; 29 | } catch (error) { 30 | console.log(error); 31 | throw new Error("Failed to get or create vAccount"); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/actions/vaccount/getPendingPayments.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "bun:test"; 2 | import { testClientSession, destructureEnv } from "../../../test/src/utils"; 3 | import { getPendingPayments } from "./getPendingPayments"; 4 | import { getVAccounts } from "./getAccounts"; 5 | 6 | describe("getPendingPayments", () => { 7 | const pendingPaymentsExample = { 8 | pendingPayments: [], 9 | claimablePayments: [], 10 | totalEfxPending: 0, 11 | totalEfxClaimable: 0, 12 | }; 13 | 14 | test("getPendingPayments() returns pendingPayments", async () => { 15 | const { actor } = destructureEnv(); 16 | const client = await testClientSession(); 17 | const [vaccount] = await getVAccounts({ client, actor }); 18 | const vAccountId = vaccount.id; 19 | const pendingPayments = await getPendingPayments({ client, vAccountId }); 20 | expect(pendingPayments).toBeDefined(); 21 | expect(pendingPayments).toMatchObject(pendingPaymentsExample); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/actions/vaccount/getPendingPayments.ts: -------------------------------------------------------------------------------- 1 | import { type UInt64, UInt128 } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import type { GetTableRowsResponse } from "../../types/helpers"; 4 | import type { Payment } from "../../@generated/types/tasks.efx"; 5 | import { getForceSettings } from "../tasks/getForceSettings"; 6 | import type { Settings } from "../../@generated/types/tasks.efx"; 7 | 8 | export const isClaimable = (p: Payment, forceSettings: Settings) => { 9 | return ( 10 | new Date(`${new Date(p.last_submission_time)}UTC`).getTime() / 1000 + 11 | forceSettings.payout_delay_sec < 12 | Date.now() / 1000 13 | ); 14 | }; 15 | 16 | export const extractAndParseQuantity = (quantity: string) => 17 | Number.parseFloat(quantity.match(/[0-9.]+/)?.[0] || "0"); 18 | 19 | export const getTimeToClaim = (p: Payment, forceSettings: Settings) => { 20 | return ( 21 | new Date(`${new Date(p.last_submission_time)}UTC`).getTime() / 1000 + 22 | forceSettings.payout_delay_sec - 23 | Date.now() / 1000 24 | ); 25 | }; 26 | 27 | export type GetPendingPaymentsArgs = { 28 | client: Client; 29 | vAccountId: number; 30 | }; 31 | 32 | export const getPendingPayments = async ({ 33 | client, 34 | vAccountId, 35 | }: GetPendingPaymentsArgs) => { 36 | const { network, provider } = client; 37 | const { contracts } = network.config.efx; 38 | 39 | const data = (await provider.v1.chain.get_table_rows({ 40 | code: contracts.tasks, 41 | scope: contracts.tasks, 42 | table: "payment", 43 | index_position: "tertiary", 44 | key_type: "i64", 45 | lower_bound: UInt128.from(vAccountId), 46 | upper_bound: UInt128.from(vAccountId), 47 | })) as GetTableRowsResponse; 48 | 49 | const forceSettings = await getForceSettings({ client }); 50 | 51 | const claimablePayments = data.rows.filter((p) => 52 | isClaimable(p, forceSettings), 53 | ); 54 | 55 | const totalEfxPending = data.rows.reduce( 56 | (acc, p) => acc + extractAndParseQuantity(p.pending.quantity) || 0, 57 | 0, 58 | ); 59 | 60 | const totalEfxClaimable = claimablePayments.reduce( 61 | (acc, p) => acc + extractAndParseQuantity(p.pending.quantity) || 0, 62 | 0, 63 | ); 64 | 65 | return { 66 | pendingPayments: data.rows, 67 | claimablePayments, 68 | totalEfxPending, 69 | totalEfxClaimable, 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /src/actions/vaccount/payout.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { destructureEnv, testClientSession } from "../../../test/src/utils"; 3 | import { payout } from "../../exports"; 4 | 5 | describe("PayOut", async () => { 6 | test("Should fail payout when there is no pending payout", async () => { 7 | const { actor } = destructureEnv(); 8 | const client = await testClientSession(); 9 | expect(async () => await payout({ client, actor })).toThrowError( 10 | "No payouts currently claimable.", 11 | ); 12 | }); 13 | 14 | test.todo("Should payout pending payments", async () => { 15 | // TODO: Should payout pending payments 16 | // Figure out flow to test this 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/actions/vaccount/payout.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type AnyAction, 3 | ExtendedAsset, 4 | type NameType, 5 | } from "@wharfkit/antelope"; 6 | import type { Client } from "../../client"; 7 | import { VAccountError } from "../../errors"; 8 | import { useEFXContracts } from "../../utils/state"; 9 | import { claimActions } from "./claim"; 10 | import { getPendingPayments } from "./getPendingPayments"; 11 | import { withdrawAction } from "./withdraw"; 12 | 13 | /* claim & withdraw EFX to VAccount */ 14 | export type PayoutArgs = { 15 | client: Client; 16 | actor: NameType; 17 | }; 18 | 19 | export const payout = async ({ client, actor }: PayoutArgs) => { 20 | if (!client.session?.vAccount) { 21 | throw new VAccountError("vAccount is not set."); 22 | } 23 | 24 | const { tasks, vaccount, token } = useEFXContracts(client); 25 | const { authorization } = client.session; 26 | 27 | const { claimablePayments, totalEfxClaimable } = await getPendingPayments({ 28 | client, 29 | vAccountId: client.session.vAccount.id, 30 | }); 31 | 32 | if (!claimablePayments.length) { 33 | throw new Error("No payouts currently claimable."); 34 | } 35 | 36 | const actions = []; 37 | 38 | if (claimablePayments) { 39 | actions.push( 40 | ...claimActions({ 41 | payments: claimablePayments, 42 | tasks, 43 | authorization, 44 | }), 45 | ); 46 | } else { 47 | throw new Error("No pending payouts found"); 48 | } 49 | 50 | // Withdraw it to the vAccount 51 | actions.push( 52 | withdrawAction({ 53 | account: vaccount, 54 | from_id: client.session.vAccount.id, 55 | to_account: actor, 56 | authorization, 57 | quantity: ExtendedAsset.from({ 58 | contract: token, 59 | quantity: `${totalEfxClaimable.toFixed(4)} EFX`, 60 | }), 61 | memo: "", 62 | }), 63 | ); 64 | 65 | const { transact } = client.session; 66 | return await transact({ actions: actions }); 67 | }; 68 | -------------------------------------------------------------------------------- /src/actions/vaccount/transfer.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test, beforeAll } from "bun:test"; 2 | import { testClientSession, destructureEnv } from "../../../test/src/utils"; 3 | import { vTransfer } from "./transfer"; 4 | import { getVAccounts, type Client } from "../../exports"; 5 | 6 | describe("vTransfer", () => { 7 | const { actor } = destructureEnv(); 8 | const receiver = "vibrantcacti"; 9 | let client: Client; 10 | const from_id = 1; 11 | const to_id = 2; 12 | const quantity = 0.0001; 13 | 14 | beforeAll(async () => { 15 | client = await testClientSession(); 16 | }); 17 | 18 | test("throws an error if session is not set", async () => { 19 | expect(async () => { 20 | await vTransfer({ client, from_id, to_id, quantity }); 21 | }).toThrow(); 22 | }); 23 | 24 | test.skip("Should return txResult, when sending 0.0001 EFX", async () => { 25 | const [vAccount] = await getVAccounts({ client, actor }); 26 | const preBalanceVAccount = Number(vAccount.balance.quantity); 27 | 28 | const [vAccountReceiver] = await getVAccounts({ 29 | client, 30 | actor: receiver, 31 | }); 32 | const preBalanceReceiver = Number(vAccountReceiver.balance.quantity); 33 | 34 | const result = await vTransfer({ 35 | client, 36 | from_id: vAccount.id, 37 | to_id: vAccountReceiver.id, 38 | quantity, 39 | }); 40 | 41 | expect(result).toBeDefined(); 42 | 43 | const [postVAccount] = await getVAccounts({ 44 | client, 45 | actor, 46 | }); 47 | 48 | const [postVAccountReceiver] = await getVAccounts({ 49 | client, 50 | actor: receiver, 51 | }); 52 | 53 | const postbalanceReceiver = Number(postVAccountReceiver.balance.quantity); 54 | const postbalance = Number(postVAccount.balance.quantity); 55 | 56 | // Make sure the balance is updated 57 | expect(postbalance).toBe(preBalanceVAccount - quantity); 58 | expect(postbalanceReceiver).toBe(preBalanceReceiver + quantity); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /src/actions/vaccount/transfer.ts: -------------------------------------------------------------------------------- 1 | import { Asset, type AnyAction } from "@wharfkit/antelope"; 2 | import type { Client } from "../../client"; 3 | import { SessionNotFoundError } from "../../errors"; 4 | import { useEFXContracts } from "../../utils/state"; 5 | import type { TransactResult } from "@wharfkit/session"; 6 | import { getVAccounts } from "./getAccounts"; 7 | 8 | export type vTransferActionArgs = { 9 | client: Client; 10 | from_id: number; 11 | to_id: number; 12 | quantity: number; 13 | }; 14 | 15 | export const vTransferAction = ({ 16 | client, 17 | to_id, 18 | from_id, 19 | quantity, 20 | }: vTransferActionArgs): AnyAction => { 21 | if (!client.session) { 22 | throw new SessionNotFoundError("Session is required for this method."); 23 | } 24 | 25 | const { actor, authorization } = client.session; 26 | const { vaccount, token } = useEFXContracts(client); 27 | 28 | return { 29 | account: vaccount, 30 | name: "vtransfer", 31 | authorization, 32 | data: { 33 | from_id, 34 | to_id, 35 | quantity: { 36 | quantity: Asset.from(quantity, "4,EFX"), 37 | contract: token, 38 | }, 39 | memo: "", 40 | payer: actor, 41 | sig: null, 42 | fee: null, 43 | }, 44 | }; 45 | }; 46 | 47 | export type vTransferArgs = { 48 | client: Client; 49 | from_id?: number; // from_id is optional, if sesion is connected, sending from actor is possible. 50 | to_id: number; 51 | quantity: number; 52 | }; 53 | 54 | export const vTransfer = async ({ 55 | client, 56 | from_id, 57 | to_id, 58 | quantity, 59 | }: vTransferArgs): Promise => { 60 | if (!client.session) { 61 | throw new SessionNotFoundError("Session is required for this method."); 62 | } 63 | const { transact, actor } = client.session; 64 | 65 | const [vaccount] = await getVAccounts({ client, actor }); 66 | 67 | const transferAction = vTransferAction({ 68 | client, 69 | to_id, 70 | from_id: from_id ?? vaccount.id, 71 | quantity, 72 | }); 73 | 74 | return await transact({ action: transferAction }); 75 | }; 76 | -------------------------------------------------------------------------------- /src/actions/vaccount/withdraw.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { testClientSession } from "../../../test/src/utils"; 3 | import { withdraw } from "../../exports"; 4 | import type { ExtendedAssetType } from "@wharfkit/antelope"; 5 | 6 | describe("withdraw", async () => { 7 | test.skip("Should withdraw vaccount EFX to wallet.", async () => { 8 | const client = await testClientSession(); 9 | const quantity: ExtendedAssetType = { 10 | quantity: "0.0001 EFX", 11 | contract: client.network.config.efx.contracts.token, 12 | }; 13 | const result = await withdraw({ client, quantity }); 14 | console.log(result); 15 | expect(result).toBeDefined(); 16 | }); 17 | 18 | test.todo("Should fail when no EFX is in vAccount", async () => { 19 | // TODO: Should fail when no EFX is in the vAccount 20 | // Figure out flow to test this 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/actions/vaccount/withdraw.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Asset, 3 | ExtendedAsset, 4 | type AnyAction, 5 | type ExtendedAssetType, 6 | type NameType, 7 | } from "@wharfkit/antelope"; 8 | import type { Client } from "../../exports"; 9 | 10 | export type WithdrawArgs = { 11 | client: Client; 12 | quantity: number; 13 | }; 14 | 15 | export const withdraw = async ({ client, quantity }: WithdrawArgs) => { 16 | if (!client.session?.vAccount) { 17 | throw new Error("vAccount is not set."); 18 | } 19 | 20 | const { transact, actor, authorization } = client.session; 21 | const { contracts } = client.network.config.efx; 22 | const quantityAsset = ExtendedAsset.from({ 23 | quantity: Asset.from(quantity, "EFX"), 24 | contract: contracts.token, 25 | }); 26 | 27 | const action = withdrawAction({ 28 | from_id: client.session.vAccount.id, 29 | to_account: actor, 30 | quantity: quantityAsset, 31 | account: contracts.vaccount, 32 | authorization, 33 | memo: "", 34 | }); 35 | 36 | return await transact({ action }); 37 | }; 38 | 39 | export type WithdrawActionArgs = { 40 | from_id: number; 41 | to_account: NameType; 42 | quantity: ExtendedAssetType; 43 | account: string; 44 | authorization: { actor: NameType; permission: NameType }[]; 45 | memo: string; 46 | }; 47 | 48 | export const withdrawAction = ({ 49 | from_id, 50 | to_account, 51 | quantity, 52 | account, 53 | authorization, 54 | }: WithdrawActionArgs): AnyAction => { 55 | return { 56 | account, 57 | name: "withdraw", 58 | authorization, 59 | data: { 60 | from_id, 61 | to_account, 62 | quantity, 63 | memo: "", 64 | }, 65 | }; 66 | }; 67 | -------------------------------------------------------------------------------- /src/cache.ts: -------------------------------------------------------------------------------- 1 | import { get as idbGet, set as idbSet } from "idb-keyval"; 2 | export const memoryCache = new Map(); 3 | 4 | export interface Cache { 5 | get(key: string): unknown; 6 | set(key: string, value: unknown): void; 7 | } 8 | 9 | export class MemoryCache implements Cache { 10 | size() { 11 | return memoryCache.size; 12 | } 13 | 14 | get(key: string): unknown { 15 | return memoryCache.get(key); 16 | } 17 | 18 | set(key: string, value: unknown): void { 19 | memoryCache.set(key, value); 20 | } 21 | } 22 | 23 | export class LocalStorageCache implements Cache { 24 | localStorage: Storage; 25 | 26 | constructor() { 27 | if (typeof localStorage === "undefined" || localStorage === null) { 28 | // eslint-disable-next-line @typescript-eslint/no-var-requires 29 | const LocalStorage = require("node-localstorage").LocalStorage; 30 | this.localStorage = new LocalStorage("./scratch"); 31 | } else { 32 | this.localStorage = localStorage; 33 | } 34 | } 35 | 36 | get(key: string): unknown { 37 | const item = this.localStorage.getItem(key); 38 | return item ? JSON.parse(item) : undefined; 39 | } 40 | 41 | set(key: string, value: unknown): void { 42 | this.localStorage.setItem(key, JSON.stringify(value, null, 2)); 43 | } 44 | } 45 | 46 | export class IDBCache implements Cache { 47 | async get(key: string): Promise { 48 | return await idbGet(key); 49 | } 50 | 51 | set(key: string, value: unknown): void { 52 | idbSet(key, value); 53 | } 54 | } 55 | 56 | export class CacheManager { 57 | private cache: Cache; 58 | 59 | constructor(cache: Cache) { 60 | this.cache = cache; 61 | } 62 | 63 | get(key: string): unknown { 64 | return this.cache.get(key); 65 | } 66 | 67 | set(key: string, value: unknown): void { 68 | this.cache.set(key, value); 69 | } 70 | } 71 | 72 | export const createCacheManager = (cache: Cache): CacheManager => { 73 | const manager = new CacheManager(cache); 74 | return manager; 75 | }; 76 | -------------------------------------------------------------------------------- /src/client.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, describe } from "bun:test"; 2 | import { createClient } from "./client"; 3 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 4 | import { destructureEnv } from "../test/src/utils"; 5 | import { Session } from "@wharfkit/session"; 6 | 7 | describe("Client", async () => { 8 | test("Create client with Session", async () => { 9 | const { network: chain, permission, actor, privateKey } = destructureEnv(); 10 | 11 | // Create wallet with privatekey 12 | const walletPlugin = new WalletPluginPrivateKey(privateKey); 13 | 14 | // Set up session with wallet 15 | const session = new Session({ actor, permission, walletPlugin, chain }); 16 | 17 | const client = await createClient({ session }); 18 | expect(client.session).toBeDefined(); 19 | expect(client.network.id).toBe(chain.id); 20 | }); 21 | 22 | test("Create client with Network", async () => { 23 | const { network } = destructureEnv(); 24 | const client = await createClient({ network }); 25 | expect(client.session).toBeDefined(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/constants/config.ts: -------------------------------------------------------------------------------- 1 | import type { AtomicConfig, IpfsConfig, RelayerConfig } from "../types/network"; 2 | 3 | export const ipfsConfig: IpfsConfig = { 4 | ipfsEndpoint: "https://ipfs.effect.ai", 5 | }; 6 | 7 | export const atomicConfig: AtomicConfig = { 8 | ipfsEndpoint: "https://atomichub-ipfs.com/ipfs/", 9 | assetEndpoint: "https://eos.atomichub.io/explorer/asset/", 10 | atomicContract: "atomicassets", 11 | }; 12 | 13 | export const relayerConfig: RelayerConfig = { 14 | eosRelayerAccount: "effectrelayr", 15 | eosRelayerPermission: "active", 16 | eosRelayerUrl: 17 | "https://vaccount-relayer-service-jungle-96xyn.ondigitalocean.app", 18 | }; 19 | 20 | export const defaultNetworkConfig = () => ({ 21 | ipfs: ipfsConfig, 22 | atomic: atomicConfig, 23 | relayer: relayerConfig, 24 | }); 25 | -------------------------------------------------------------------------------- /src/constants/network.ts: -------------------------------------------------------------------------------- 1 | import type { Network } from "../types/network"; 2 | import { defaultNetworkConfig } from "./config"; 3 | 4 | export const jungle4: Network = { 5 | name: "jungle4", 6 | url: "https://jungle4.cryptolions.io/", 7 | id: "73e4385a2708e6d7048834fbc1079f2fabb17b3c125b146af438971e90716c4d", 8 | config: { 9 | efx: { 10 | token: { 11 | symbol: "EFX", 12 | precision: 4, 13 | }, 14 | contracts: { 15 | tasks: "effecttasks2", 16 | token: "efxtoken1112", 17 | usdt: "tethertether", 18 | eostoken: "eosio.token", 19 | stake: "efxstake1111", 20 | feepool: "efxfeepool11", 21 | proposals: "efxproposals", 22 | vaccount: "efxaccount11", 23 | dao: "theeffectdao", 24 | }, 25 | }, 26 | // use default values for ipfs, atomic, and relayer 27 | ...defaultNetworkConfig(), 28 | }, 29 | }; 30 | 31 | export const eos: Network = { 32 | name: "eos", 33 | url: "https://eos.greymass.com/", 34 | id: "aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906", 35 | config: { 36 | efx: { 37 | token: { 38 | symbol: "EFX", 39 | precision: 4, 40 | }, 41 | contracts: { 42 | tasks: "tasks.efx", 43 | token: "effecttokens", 44 | usdt: "tethertether", 45 | eostoken: "eosio.token", 46 | stake: "efxstakepool", 47 | feepool: "feepool.efx", 48 | proposals: "daoproposals", 49 | vaccount: "vaccount.efx", 50 | dao: "theeffectdao", 51 | }, 52 | }, 53 | // use default values for ipfs, atomic, and relayer 54 | ...defaultNetworkConfig(), 55 | }, 56 | }; 57 | 58 | export const networks = [eos, jungle4]; 59 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | export class AuthenticationError extends Error {} 2 | export class SessionNotFoundError extends Error {} 3 | export class TransactionError extends Error {} 4 | export class NotFoundError extends Error {} 5 | export class VAccountError extends Error { 6 | constructor( 7 | message: string, 8 | public retry = 0, 9 | ) { 10 | super(message); 11 | } 12 | } 13 | 14 | export class TaskIpfsError extends Error { 15 | constructor( 16 | message: string, 17 | public retry = 0, 18 | ) { 19 | super(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/exports/constants.ts: -------------------------------------------------------------------------------- 1 | export * from "./../constants/config"; 2 | export * from "./../constants/network"; 3 | export * from "../utils/structs"; 4 | export * from "../utils/variants"; 5 | -------------------------------------------------------------------------------- /src/exports/errors.ts: -------------------------------------------------------------------------------- 1 | export * from "./../errors"; 2 | -------------------------------------------------------------------------------- /src/exports/template.ts: -------------------------------------------------------------------------------- 1 | export * from "./../template/template"; 2 | -------------------------------------------------------------------------------- /src/exports/types.ts: -------------------------------------------------------------------------------- 1 | export * from "../types/helpers"; 2 | export * from "../types/network"; 3 | export * from "../types/user"; 4 | -------------------------------------------------------------------------------- /src/exports/version.ts: -------------------------------------------------------------------------------- 1 | export const version = "2.0.0"; 2 | -------------------------------------------------------------------------------- /src/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | // Some stricter flags (disabled by default) 23 | "noUnusedLocals": false, 24 | "noUnusedParameters": false, 25 | "noPropertyAccessFromIndexSignature": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@effectai/sdk", 3 | "version": "2.0.2", 4 | "description": "Effect Network Javscript/Typescript SDK (for [https://effect.network](https://effect.network))", 5 | "main": "./dist/exports/index.js", 6 | "module": "./dist/exports/index.js", 7 | "browser": "dist/exports/index.js", 8 | "types": "./dist/exports/index.d.ts", 9 | "files": ["dist"], 10 | "type": "module", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/effectai/effect-js.git" 14 | }, 15 | "keywords": ["efx", "AI", "blockchain", "microtasks"], 16 | "author": { 17 | "name": "Effect-AI", 18 | "url": "https://effect.network", 19 | "email": "hello@effect.ai" 20 | }, 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/effectai/effect-js/issues" 27 | }, 28 | "homepage": "https://github.com/effectai/effect-js#readme", 29 | "devDependencies": { 30 | "@types/bun": "latest" 31 | }, 32 | "dependencies": { 33 | "@wharfkit/antelope": "^1.0.7", 34 | "@wharfkit/session": "^1.2.8", 35 | "ajv": "^8.12.0", 36 | "atomicassets": "^1.5.1", 37 | "idb-keyval": "^6.2.1", 38 | "node-localstorage": "^3.0.5" 39 | }, 40 | "peerDependencies": { 41 | "typescript": "^5.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/session.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | NameType, 3 | PermissionLevelType, 4 | Session, 5 | TransactArgs, 6 | } from "@wharfkit/session"; 7 | import { TxState, waitForTransaction } from "./utils/transaction"; 8 | import type { Account } from "./@generated/types/vaccount.efx"; 9 | 10 | export class EffectSession { 11 | public readonly wharfKitSession: Session; 12 | 13 | public readonly actor: NameType; 14 | public readonly permission: NameType; 15 | public readonly permissionLevel: PermissionLevelType; 16 | public readonly authorization: { actor: NameType; permission: NameType }[]; 17 | 18 | private _vAccount: Account | null; 19 | 20 | get vAccount(): Account | null { 21 | return this._vAccount; 22 | } 23 | 24 | constructor(session: Session, vAccount: Account) { 25 | this.actor = session.actor; 26 | this.permission = session.permission; 27 | this.permissionLevel = session.permissionLevel; 28 | this.wharfKitSession = session; 29 | this.authorization = [{ actor: this.actor, permission: this.permission }]; 30 | this._vAccount = vAccount; 31 | } 32 | 33 | public transact = async (args: TransactArgs) => { 34 | // Start the transaction 35 | const transaction = await this.wharfKitSession.transact({ 36 | ...args, 37 | }); 38 | 39 | //wait for TX to be IN BLOCK 40 | await waitForTransaction( 41 | transaction.response?.transaction_id, 42 | this.wharfKitSession.client.v1.chain, 43 | TxState.IN_BLOCK, 44 | ); 45 | 46 | return transaction; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /src/template/template.ts: -------------------------------------------------------------------------------- 1 | import templateScript from "./templateScript"; 2 | 3 | export class Template { 4 | public html: string; 5 | public placeholders: { 6 | [key: string]: string; 7 | }; 8 | public options: object; 9 | public info: object; 10 | private rendered!: string; 11 | 12 | constructor(html: string, placeholders = {}, options = {}, info = {}) { 13 | this.html = html; 14 | this.placeholders = placeholders; 15 | this.options = options; 16 | this.info = info; 17 | } 18 | 19 | public render(): string { 20 | this.replacePlaceholders(); 21 | this.injectJSVar("FORCE_OPTIONS", this.options); 22 | this.injectJSVar("FORCE_INFO", this.info); 23 | this.injectJSVar("FORCE_PLACEHOLDERS", this.placeholders); 24 | this.injectHTML(templateScript); 25 | this.wrapForm(); 26 | return this.rendered; 27 | } 28 | 29 | static htmlEntities(str: string | number): string { 30 | return String(str) 31 | .replace(/&/g, "&") 32 | .replace(//g, ">") 34 | .replace(/"/g, """) 35 | .replace(/'/g, "'") 36 | .replace(/`/g, "`"); 37 | } 38 | 39 | private replacePlaceholders() { 40 | this.rendered = this.html.replace( 41 | /\$\{\s?(\w+)\s?\|?\s?(\w*)\s?\}/g, 42 | (all, name, option) => { 43 | if (name in this.placeholders) { 44 | let value = this.placeholders[name]; 45 | if (Array.isArray(value) || value === Object(value)) { 46 | value = JSON.stringify(value); 47 | } 48 | switch (option) { 49 | case "raw": 50 | case "html": 51 | return value; 52 | default: 53 | return Template.htmlEntities(value); 54 | } 55 | } 56 | return ""; 57 | }, 58 | ); 59 | } 60 | 61 | private injectHTML(html: string, prepend = false) { 62 | if (prepend) { 63 | this.rendered = html + this.rendered; 64 | } else { 65 | this.rendered += html; 66 | } 67 | } 68 | 69 | private injectJSVar(name: string, value: unknown) { 70 | const html = ``; 71 | this.injectHTML(html, true); 72 | } 73 | 74 | private injectJSFile(url: string, prepend = false) { 75 | const html = ``; 76 | this.injectHTML(html, prepend); 77 | } 78 | 79 | private injectCSSFile(url: string, prepend = false) { 80 | const html = ``; 81 | this.injectHTML(html, prepend); 82 | } 83 | 84 | private wrapForm() { 85 | this.rendered = `
${this.rendered}
`; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/types/helpers.ts: -------------------------------------------------------------------------------- 1 | export type GetTableRowsResponse = { 2 | rows: T[]; 3 | more: boolean; 4 | next_key?: Key; 5 | }; 6 | -------------------------------------------------------------------------------- /src/types/network.ts: -------------------------------------------------------------------------------- 1 | import type { ChainDefinitionType } from "@wharfkit/session"; 2 | 3 | export type Network = ChainDefinitionType & { 4 | config: NetworkConfig; 5 | }; 6 | export interface AtomicConfig { 7 | atomicContract: string; 8 | ipfsEndpoint: string; 9 | assetEndpoint: string; 10 | } 11 | 12 | export interface EfxConfig { 13 | token: { 14 | symbol: string; 15 | precision: number; 16 | }; 17 | contracts: { 18 | tasks: string; 19 | token: string; 20 | usdt: string; 21 | eostoken: string; 22 | stake: string; 23 | feepool: string; 24 | proposals: string; 25 | vaccount: string; 26 | dao: string; 27 | }; 28 | } 29 | 30 | export interface RelayerConfig { 31 | eosRelayerAccount: string; 32 | eosRelayerPermission: string; 33 | eosRelayerUrl: string; 34 | } 35 | 36 | export interface IpfsConfig { 37 | ipfsEndpoint: string; 38 | } 39 | 40 | export interface NetworkConfig { 41 | ipfs: IpfsConfig; 42 | atomic: AtomicConfig; 43 | efx: EfxConfig; 44 | relayer: RelayerConfig; 45 | } 46 | -------------------------------------------------------------------------------- /src/types/user.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Vaccount Interface, Virtual Account for Effect Network 3 | * @interface 4 | * @property {number} id - Vaccount ID 5 | * @property {number} nonce - Vaccount nonce 6 | * @property {array} address - Vaccount address ['name', 'eosAccName'] 7 | * @property {string} balance - Vaccount balance 8 | * @property {string} contract - Vaccount contract 9 | * @property {string} quantity - Vaccount quantity 10 | */ 11 | 12 | export interface DefiBoxPair { 13 | id: number; 14 | token0: { 15 | contract: string; 16 | symbol: string; 17 | }; 18 | token1: { 19 | contract: string; 20 | symbol: string; 21 | }; 22 | reserve0: string; 23 | reserve1: string; 24 | liquidity_token: number; 25 | price0_last: string; 26 | price1_last: string; 27 | price0_cumulative_last: string; 28 | price1_cumulative_last: number; 29 | block_time_last: string; 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/keys.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ABIEncoder, 3 | Checksum256, 4 | Name, 5 | type NameType, 6 | UInt32, 7 | UInt64, 8 | } from "@wharfkit/antelope"; 9 | import { VAddress } from "./variants"; 10 | 11 | export function createCompositeU64Key(lowerId: number, upperId: number) { 12 | // Check if lowerId or upperId isn't of type number 13 | if (typeof lowerId !== "number" || typeof upperId !== "number") { 14 | throw new TypeError("Both lowerId and upperId must be numbers"); 15 | } 16 | 17 | const byteArray = new Uint8Array(8); 18 | byteArray.set(UInt32.from(lowerId).byteArray, 0); 19 | byteArray.set(UInt32.from(upperId).byteArray, 4); 20 | 21 | return UInt64.from(byteArray); 22 | } 23 | 24 | export const generateCheckSumForVAccount = ( 25 | actor: NameType, 26 | tokenContract: string, 27 | ): Checksum256 => { 28 | const enc = new ABIEncoder(32); 29 | Name.from(tokenContract).toABI(enc); 30 | const vaddr = VAddress.from(actor); 31 | enc.writeByte(vaddr.variantIdx); 32 | vaddr.value.toABI(enc); 33 | 34 | const arr = new Uint8Array(32); 35 | arr.set(enc.getData(), 0); 36 | const keycs = Checksum256.from(arr); 37 | 38 | return keycs; 39 | }; 40 | -------------------------------------------------------------------------------- /src/utils/state.ts: -------------------------------------------------------------------------------- 1 | // Helper functions to extract data from client state (e.g. session or config) 2 | import type { Client } from "../client"; 3 | 4 | export const useEFXContracts = (client: Client) => { 5 | const { contracts } = client.network.config.efx; 6 | 7 | return contracts; 8 | }; 9 | -------------------------------------------------------------------------------- /src/utils/structs.ts: -------------------------------------------------------------------------------- 1 | import { type Asset, type NameType, Struct } from "@wharfkit/antelope"; 2 | 3 | @Struct.type("extended_symbol") 4 | export class ExtendedSymbol extends Struct { 5 | static abiName = "extended_symbol"; 6 | static abiFields = [ 7 | { name: "contract", type: "name" }, 8 | { name: "sym", type: "symbol" }, 9 | ]; 10 | constructor(sym: Asset.SymbolType, contract: NameType) { 11 | super({ sym, contract }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/transaction.ts: -------------------------------------------------------------------------------- 1 | import type { ChainAPI, Checksum256Type } from "@wharfkit/antelope"; 2 | 3 | export enum TxState { 4 | EXECUTED = "EXECUTED", 5 | SOFT_FAIL = "soft_fail", 6 | HARD_FAIL = "hard_fail", 7 | EXPIRED = "EXPIRED", 8 | IRREVERSIBLE = "IRREVERSIBLE", 9 | IN_BLOCK = "IN_BLOCK", 10 | } 11 | 12 | export function waitForTransaction( 13 | transactionId: Checksum256Type, 14 | context: ChainAPI, 15 | state: TxState = TxState.IRREVERSIBLE, 16 | maxRetries = 3, 17 | ) { 18 | return new Promise((resolve, reject) => { 19 | let attempt = 0; 20 | const interval = setInterval(async () => { 21 | try { 22 | attempt++; 23 | const response = await context.get_transaction_status(transactionId); 24 | if ( 25 | response.state === TxState.SOFT_FAIL || 26 | response.state === TxState.HARD_FAIL || 27 | response.state === TxState.EXPIRED 28 | ) { 29 | clearInterval(interval); 30 | reject(response); 31 | } 32 | 33 | if (response?.state === state) { 34 | clearInterval(interval); 35 | resolve(response); 36 | } 37 | } catch (error) { 38 | if (attempt > maxRetries) { 39 | clearInterval(interval); 40 | reject(error); 41 | } 42 | } 43 | }, 3000); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /src/utils/variants.ts: -------------------------------------------------------------------------------- 1 | import { Checksum160, Name, Variant } from "@wharfkit/antelope"; 2 | 3 | @Variant.type("vaddress", [Checksum160, Name]) 4 | export class VAddress extends Variant { 5 | declare value: Checksum160 | Name; 6 | } 7 | -------------------------------------------------------------------------------- /test/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { CampaignWithInfo } from "../../src/exports"; 2 | 3 | export const campaign: CampaignWithInfo = { 4 | id: 1, 5 | reservations_done: 1, 6 | total_submissions: 2, 7 | total_tasks: 1, 8 | active_batch: 1, 9 | num_batches: 1, 10 | owner: ["name", "efxefxefxefx"], 11 | paused: false, 12 | content: { 13 | field_0: 0, 14 | field_1: "QmVKwq3bYM6cPW6kstpiq4WYckWRtdfJnzAmms2iMyGqQg", 15 | }, 16 | max_task_time: 3600, 17 | reward: { 18 | quantity: "0.0100 EFX", 19 | contract: "efxtoken1112", 20 | }, 21 | qualis: [], 22 | info: { 23 | version: 1.1, 24 | title: "Labelstudio OCR (LAION)", 25 | description: 26 | "You are contributing to a dataset for conversational style chatbots.", 27 | instructions: "Some instructions here", 28 | template: "Template here", 29 | input_schema: null, 30 | output_schema: null, 31 | image: "", 32 | category: "", 33 | example_task: "", 34 | estimated_time: 10, 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /test/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | PrivateKey, 3 | type PrivateKeyType, 4 | Session, 5 | } from "@wharfkit/session"; 6 | import { WalletPluginPrivateKey } from "@wharfkit/wallet-plugin-privatekey"; 7 | import { jungle4, } from "../../src/exports"; 8 | import { createClient } from "../../src/client"; 9 | import type { Client } from "../../src/client"; 10 | import type { Network } from "../../src/types/network"; 11 | 12 | declare module "bun" { 13 | interface Env { 14 | TESTNET_PERMISSION: string; 15 | TESTNET_NETWORK_NAME: string; 16 | TESTNET_ACTOR: string; 17 | TESTNET_PRIVATE_KEY: string; 18 | MAINNET_PERMISSION: string; 19 | MAINNET_NETWORK_NAME: string; 20 | MAINNET_ACTOR: string; 21 | MAINNET_PRIVATE_KEY: string; 22 | } 23 | } 24 | 25 | export interface testEnv { 26 | network: Network; 27 | networkName: string; 28 | permission: string; 29 | actor: string; 30 | privateKey: PrivateKeyType; 31 | } 32 | 33 | export const destructureEnv = () => { 34 | return { 35 | network: jungle4, 36 | networkName: process.env.TESTNET_NETWORK_NAME, 37 | permission: process.env.TESTNET_PERMISSION!, 38 | actor: process.env.TESTNET_ACTOR!, 39 | privateKey: PrivateKey.from(process.env.TESTNET_PRIVATE_KEY!), 40 | }; 41 | }; 42 | 43 | export const testClientSession = async (): Promise => { 44 | // Retrieve parameters for session. 45 | const { network: chain, permission, actor, privateKey } = destructureEnv(); 46 | 47 | if (!privateKey) { 48 | throw new Error("Private key not found"); 49 | } 50 | 51 | // Setup wallet plugin with private key 52 | const walletPlugin = new WalletPluginPrivateKey(privateKey); 53 | 54 | const session = new Session({ actor, permission, walletPlugin, chain }); 55 | 56 | // Create client 57 | const client = await createClient({ session }); 58 | 59 | return client; 60 | }; 61 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /// 2 | { 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "downlevelIteration": true, 6 | "esModuleInterop": false, 7 | "importHelpers": true, 8 | "experimentalDecorators": true, 9 | "isolatedModules": true, 10 | "lib": ["DOM", "ES2020"], 11 | "moduleResolution": "node", 12 | "module": "ESNext", 13 | "sourceMap": true, 14 | "declaration": true, 15 | "strict": true, 16 | "target": "ES2021", 17 | "outDir": "dist", 18 | "skipLibCheck": true 19 | }, 20 | "exclude": ["node_modules/**/*", "**/*.test.ts", "**/dist/**"], 21 | "include": ["src/**/*", "abis/**/*", "test/testHelper.ts"] 22 | } 23 | --------------------------------------------------------------------------------