diff --git a/.github/workflows/deploy-contracts.yml b/.github/workflows/deploy-contracts.yml new file mode 100644 index 00000000..c59f4dc5 --- /dev/null +++ b/.github/workflows/deploy-contracts.yml @@ -0,0 +1,137 @@ +name: "Deploy Contracts" + +on: + workflow_dispatch: + inputs: + provider_url: + description: 'Provider url' + required: true + default: 'https://node.swayswap.io/graphql' + type: string + wallet_secret: + description: 'Wallet secret used to deploy and provide initial liquidity' + type: string + byte_price: + description: 'Min byte price required from the provider' + type: number + gas_price: + description: 'Min gas price required from the provider' + type: number + initiate_supply: + description: 'Should initialize the pool?' + required: true + default: true + type: boolean + commit_changes: + description: 'Commit .env.production on the current branch' + required: true + default: true + type: boolean + +env: + RUST_VERSION: 1.61.0 + FORC_VERSION: 0.15.2 + NODE_VERSION: 16 + PNPM_VERSION: 7.0.0 + COMPOSE_VERSION: 2.6.0 + WALLET_SECRET: ${{ github.event.inputs.wallet_secret || secrets.WALLET_SECRET }} + PROVIDER_URL: ${{ github.event.inputs.provider_url || 'https://node.swayswap.io/graphql' }} + BYTE_PRICE: ${{ github.event.inputs.byte_price || 1 }} + GAS_PRICE: ${{ github.event.inputs.gas_price || 1 }} + TOKEN_AMOUNT: ${{ github.event.inputs.token_amount }} + ETH_AMOUNT: ${{ github.event.inputs.eth_amount }} + OUTPUT_ENV: .env.production + +jobs: + cancel-previous-run: + name: Cancel previous actions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: n1hility/cancel-previous-runs@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + test_inputs: + runs-on: ubuntu-latest + steps: + - name: Check provider_url format + run: | + if ! [[ "${{ github.event.inputs.provider_url }}" =~ ^https?:\/\/([a-z0-9\.-]){1,}(:[0-9]{1,4})?\/graphql$ ]]; then + echo "Provider url is not valid"; + process 1; + fi + shell: bash + + build-and-deploy: + needs: test_inputs + name: Build and deploy + runs-on: ubuntu-latest + if: github.ref != 'refs/heads/master' + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ env.RUST_VERSION }} + override: true + # selecting a toolchain either by action or manual `rustup` calls should happen + # before the cache plugin, as it uses the current rustc version as its cache key + - uses: Swatinem/rust-cache@v1 + + - name: Set git config + run: | + git config --global core.bigfilethreshold 100m + + - name: Install Forc + run: | + curl -sSLf https://github.com/FuelLabs/sway/releases/download/v${{ env.FORC_VERSION }}/forc-binaries-linux_amd64.tar.gz -L -o forc.tar.gz + tar -xvf forc.tar.gz + chmod +x forc-binaries/forc + mv forc-binaries/forc /usr/local/bin/forc + shell: bash + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: "https://registry.npmjs.org" + + - name: Cache PNPM modules + uses: actions/cache@v2 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}- + + - name: Setup PNPM + uses: pnpm/action-setup@v2.1.0 + with: + version: ${{ env.PNPM_VERSION }} + run_install: true + + - name: Setup scripts + run: | + pnpm scripts:setup + + - name: Deploy contracts + run: | + pnpm exec swayswap-scripts run + + - name: Initiate token contract and liquidity pool + if: ${{ github.event.inputs.initiate_supply }} + run: | + pnpm contracts:init-pool + env: + NODE_ENV: production + + - name: Commit .env.production + if: ${{ github.event.inputs.commit_changes }} + uses: EndBug/add-and-commit@v9 + with: + message: 'chore: update contract ids' + add: './packages/app/.env.production' diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 80f8ba14..4ce00738 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -3,7 +3,6 @@ name: GitHub Pages on: release: types: [published] - workflow_dispatch: env: NODE_VERSION: "16" @@ -41,8 +40,8 @@ jobs: CI: false PUBLIC_URL: "/${{ github.event.repository.name }}" VITE_FUEL_PROVIDER_URL: "https://node.swayswap.io/graphql" - VITE_CONTRACT_ID: "0x67ae68ddea9f9212d96c7b0f1ece1db522b0cfd688d96ed0bdd7d171b789e593" - VITE_TOKEN_ID: "0xf7a2eb8a271a3ea73d6fb8756e272f4a1687d9522acf2ded4454f5d0d5f6a660" + VITE_CONTRACT_ID: "0x4d7e56f79ad160ecd8f0da0833edd62044026bdab65275fa3a34e6a855b96ccc" + VITE_TOKEN_ID: "0xe3ee9322336a734296dd53afe9b90b1bfc7c716762844669b7895ca9ad438b88" run: | pnpm build diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index b0b3ddd6..2d1015e8 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -2,11 +2,11 @@ name: "CI" on: pull_request: - types: [opened, synchronize, ready_for_review, edited, closed] + types: [opened, synchronize, edited, closed] env: RUST_VERSION: 1.61.0 - FORC_VERSION: 0.14.5 + FORC_VERSION: 0.15.2 NODE_VERSION: 16 PNPM_VERSION: 7.0.0 COMPOSE_VERSION: 2.6.0 @@ -37,6 +37,32 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: "https://registry.npmjs.org" + + - name: Cache PNPM modules + uses: actions/cache@v2 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}- + + - name: Setup PNPM + uses: pnpm/action-setup@v2.1.0 + with: + version: ${{ env.PNPM_VERSION }} + run_install: true + + # Check lint as early as possible to avoid + # Long fail CI and fail on this step + - name: Lint + run: | + pnpm lint + - name: Install toolchain uses: actions-rs/toolchain@v1 with: @@ -76,32 +102,6 @@ jobs: run: | ./scripts/test-contracts.sh - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: ${{ env.NODE_VERSION }} - registry-url: "https://registry.npmjs.org" - - - name: Cache PNPM modules - uses: actions/cache@v2 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}- - - - name: Setup PNPM - uses: pnpm/action-setup@v2.1.0 - with: - version: ${{ env.PNPM_VERSION }} - run_install: true - - # Check lint as early as possible to avoid - # Long fail CI and fail on this step - - name: Lint - run: | - pnpm lint - - name: Setup Docker uses: docker/login-action@v2 with: diff --git a/.gitignore b/.gitignore index 8a890e30..3031cda5 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,6 @@ storybook-static # general contracts/token_contract/.rustc_info.json .vercel + +# Local actions to test CI using ACT +act-actions \ No newline at end of file diff --git a/README.md b/README.md index 492865e3..6678183b 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,11 @@ Built with an entirely new language ([Sway](https://fuellabs.github.io/sway/late - [📦 - Install dependencies](docs/GETTING_STARTED.md#---install-dependencies) - [📒 - Run Local Node](docs/GETTING_STARTED.md#---run-local-node) - [💻 - Run Web App](docs/GETTING_STARTED.md#---run-web-app) - - [✨ - First steps](docs/GETTING_STARTED.md#---first-steps) - [📗 Project overview](docs/GETTING_STARTED.md#-project-overview) - [🧰 Useful scripts](docs/GETTING_STARTED.md#-useful-scripts) + - [Running tests](docs/GETTING_STARTED.md#running-tests) + - [Run tests on development mode](docs/GETTING_STARTED.md#running-tests-1) + - [Run tests on a Local TEST Environment](docs/GETTING_STARTED.md#run-tests-on-a-local-test-environment) - [Contribution Guide](docs/CONTRIBUTE_GUIDE.md) - [Finding Something to Work On](docs/CONTRIBUTE_GUIDE.md#finding-something-to-work-on) - [Contribution Flow](docs/CONTRIBUTE_GUIDE.md#contribution-flow) diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index d4b00934..1d1c56a6 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -7,7 +7,7 @@ This project includes Front-End and Contracts because of this we expect the curr - [Node.js v16.15.0 or latest stable](https://nodejs.org/en/) we recommend use [nvm](https://github.com/nvm-sh/nvm) to install. - [PNPM v7.1.7 or latest stable](https://pnpm.io/installation/) - [Rust toolchain v0.16.0 or latest stable](https://www.rust-lang.org/tools/install) -- [Forc v0.14.5 or latest stable](https://fuellabs.github.io/sway/latest/introduction/installation.html) +- [Forc v0.15.2](https://fuellabs.github.io/sway/latest/introduction/installation.html) - [Docker v0.8.2 or latest stable](https://docs.docker.com/get-docker/) - [Docker Compose v2.6.0 or latest stable](https://docs.docker.com/get-docker/) @@ -36,7 +36,9 @@ In this step, we are going to; - launch a local `fuel-core` node; - launch a local `faucet` API; - Setup `swayswap-scripts`; -- Build and Deploy the `swayswap contracts`. +- Build and Deploy the `swayswap contracts`; +- Initialize `token contract`; +- Initialize pool with liquidity `ETH <> DAI`. ```sh pnpm services:setup @@ -51,16 +53,6 @@ you browser [http://localhost:3000](http://localhost:3000). pnpm dev ``` -### ✨ - First steps - -This guided step-by-step tutorial will allow you to create your first liquidity pool and play around with the application - -1. As you go trough the `Welcome page` you should have already mintrf some `ETH`, you can get more by clicking on the `faucet button`; -2. Go to [http://localhost:3000/mint](http://localhost:4000/mint) and mint some DAI by clicking `Mint tokens`; -3. Now you need to create a pool, you can navigate by clicking `pool` and `add liquidity` or access [http://localhost:3000/pool/add-liquidity](http://localhost:3000/pool/add-liquidity); -4. Set the inputs with some `ETH` and `DAI` and click `Create liquidity`. -5. 🎉🎉 You are all set! Now you can go back to the swap page or add more liquidity, have fun! - ## 📗 Project overview This section has a brief description of each directory, more details can be found inside each package, by clicking on the links. @@ -101,7 +93,7 @@ Please make sure you have follow the steps; - [📦 - Install dependencies](docs/GETTING_STARTED.md#---install-dependencies) - [📒 - Run Local Node](docs/GETTING_STARTED.md#---run-local-node) -## Run tests +## Run tests on development mode We are going to run all tests, against the node and contract configured on the `packages/app/.env` or `packages/app/.env.test` if the file exists. @@ -117,6 +109,7 @@ With this command we are going to; - launch a local `test` specific `faucet` API; - Setup `swayswap-scripts`; - Build and Deploy the `swayswap contracts` to the `test` node. +- Initialize `token contract` deployed on the `test` node. - Create a `packages/app/.env.test` - Run all tests against the configs `packages/app/.env.test` - Delete the local `test` specific `fuel-core` node; diff --git a/package.json b/package.json index 4cd643eb..df641d70 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "contracts": "pnpm exec swayswap-scripts run", "contracts:build": "pnpm exec swayswap-scripts build", "contracts:deploy": "pnpm exec swayswap-scripts deploy", + "contracts:init": "pnpm run --filter swayswap-app contracts:init", + "contracts:init-pool": "pnpm run --filter swayswap-app contracts:init --init-pool", "cy:open": "cypress open", "cy:run": "cypress run --headless", "dev": "turbo run dev --parallel", @@ -38,13 +40,13 @@ "prettier:format": "prettier --write .", "scripts:setup": "turbo run build --filter=swayswap-scripts && pnpm install", "services:clean": "make -C docker services-clean", - "services:setup": "run-s scripts:setup services:run contracts", + "services:setup": "run-s scripts:setup services:run contracts contracts:init-pool", "services:run": "make -C docker services-run", - "services:reset": "run-s services:clean services:run contracts", + "services:reset": "run-s services:clean services:setup", "services:clean-test": "make -C docker services-clean-test", - "services:setup-test": "NODE_ENV=test run-s scripts:setup create:test-env services:run-test contracts", + "services:setup-test": "NODE_ENV=test run-s scripts:setup create:test-env services:run-test contracts contracts:init", "services:run-test": "make -C docker services-run-test", - "services:reset-test": "NODE_ENV=test run-s services:clean-test services:run-test contracts", + "services:reset-test": "NODE_ENV=test run-s services:clean-test services:setup-test", "test": "turbo run test -- --passWithNoTests --runInBand", "test:coverage": "turbo run test -- --collectCoverage --passWithNoTests --runInBand", "test:clear": "jest --clearCache", diff --git a/packages/app/.env.production b/packages/app/.env.production index 751cbbdc..750fb8b0 100644 --- a/packages/app/.env.production +++ b/packages/app/.env.production @@ -5,5 +5,5 @@ VITE_FUEL_PROVIDER_URL=https://node.swayswap.io/graphql VITE_FUEL_FAUCET_URL=https://faucet-fuel-core.swayswap.io/dispense VITE_FAUCET_RECAPTCHA_KEY=6Ld3cEwfAAAAAMd4QTs7aO85LyKGdgj0bFsdBfre -VITE_CONTRACT_ID=0x67ae68ddea9f9212d96c7b0f1ece1db522b0cfd688d96ed0bdd7d171b789e593 -VITE_TOKEN_ID=0xf7a2eb8a271a3ea73d6fb8756e272f4a1687d9522acf2ded4454f5d0d5f6a660 +VITE_CONTRACT_ID=0x4d7e56f79ad160ecd8f0da0833edd62044026bdab65275fa3a34e6a855b96ccc +VITE_TOKEN_ID=0xe3ee9322336a734296dd53afe9b90b1bfc7c716762844669b7895ca9ad438b88 diff --git a/packages/app/cypress/e2e/App.cy.ts b/packages/app/cypress/e2e/App.cy.ts index c2e632c6..6f433d14 100644 --- a/packages/app/cypress/e2e/App.cy.ts +++ b/packages/app/cypress/e2e/App.cy.ts @@ -1,6 +1,6 @@ describe('App flow', () => { it('should execute whole app flow', () => { - cy.visit('/ '); + cy.visit('/'); cy.contains('button', /Launch app/i).click(); diff --git a/packages/app/load.envs.ts b/packages/app/load.envs.ts index ab3c0154..72f8f2c7 100644 --- a/packages/app/load.envs.ts +++ b/packages/app/load.envs.ts @@ -14,6 +14,6 @@ function getEnvName() { [getEnvName(), '.env'].forEach((envFile) => { if (!envFile) return; config({ - path: resolve(process.cwd(), envFile), + path: resolve(__dirname, envFile), }); }); diff --git a/packages/app/package.json b/packages/app/package.json index 44bf725f..4e3157a1 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -8,6 +8,7 @@ "create404": "cp ./dist/index.html ./dist/404.html", "dev": "vite", "gh-preview": "sh ./scripts/gh-pages-preview.sh", + "contracts:init": "pnpm exec ts-node ./scripts/contracts-init", "postinstall": "sh ./scripts/postinstall.sh", "preview": "vite preview", "test": "jest --verbose", @@ -17,8 +18,8 @@ "@ethersproject/bignumber": "^5.6.2", "@ethersproject/random": "^5.6.1", "@ethersproject/units": "^5.6.1", - "@fontsource/raleway": "^4.5.9", "@fontsource/inter": "^4.5.11", + "@fontsource/raleway": "^4.5.9", "@headlessui/react": "^1.6.4", "@radix-ui/react-accordion": "^0.1.6", "@radix-ui/react-alert-dialog": "^0.1.7", @@ -87,6 +88,7 @@ "postcss": "^8.4.14", "postcss-import": "^14.1.0", "tailwindcss": "^3.0.24", + "ts-node": "^10.8.1", "typescript": "^4.7.3", "vite": "^2.9.10" } diff --git a/packages/app/scripts/contracts-init/index.ts b/packages/app/scripts/contracts-init/index.ts new file mode 100644 index 00000000..f8b756a8 --- /dev/null +++ b/packages/app/scripts/contracts-init/index.ts @@ -0,0 +1,34 @@ +import type { Overrides } from 'fuels'; +import { Wallet } from 'fuels'; + +import '../../load.envs'; +import './loadDockerEnv'; +import { ExchangeContractAbi__factory, TokenContractAbi__factory } from '../../src/types/contracts'; + +import { initializePool } from './initializePool'; +import { initializeTokenContract } from './initializeTokenContract'; + +const { WALLET_SECRET, PROVIDER_URL, BYTE_PRICE, GAS_PRICE, VITE_CONTRACT_ID, VITE_TOKEN_ID } = + process.env; + +if (!WALLET_SECRET) { + process.stdout.write('WALLET_SECRET is not detected!\n'); + process.exit(1); +} + +async function main() { + const wallet = new Wallet(WALLET_SECRET!, PROVIDER_URL); + const exchangeContract = ExchangeContractAbi__factory.connect(VITE_CONTRACT_ID!, wallet); + const tokenContract = TokenContractAbi__factory.connect(VITE_TOKEN_ID!, wallet); + const overrides: Overrides = { + gasPrice: BigInt(GAS_PRICE || 0), + bytePrice: BigInt(BYTE_PRICE || 0), + }; + + await initializeTokenContract(tokenContract, overrides); + if (process.argv.includes('--init-pool')) { + await initializePool(tokenContract, exchangeContract, overrides); + } +} + +main(); diff --git a/packages/app/scripts/contracts-init/initializePool.ts b/packages/app/scripts/contracts-init/initializePool.ts new file mode 100644 index 00000000..1c971ba7 --- /dev/null +++ b/packages/app/scripts/contracts-init/initializePool.ts @@ -0,0 +1,46 @@ +import type { Overrides } from 'fuels'; +import { NativeAssetId } from 'fuels'; + +import type { ExchangeContractAbi, TokenContractAbi } from '../../src/types/contracts'; + +const { TOKEN_AMOUNT, ETH_AMOUNT } = process.env; + +export async function initializePool( + tokenContract: TokenContractAbi, + exchangeContract: ExchangeContractAbi, + overrides: Overrides +) { + const wallet = tokenContract.wallet!; + const tokenAmount = BigInt(TOKEN_AMOUNT || '2000000000000000'); + const ethAmount = BigInt(ETH_AMOUNT || '1000500000000'); + const address = { + value: wallet.address, + }; + const tokenId = { + value: tokenContract.id, + }; + + await tokenContract.submit.mint_coins(tokenAmount, overrides); + await tokenContract.submit.transfer_token_to_output(tokenAmount, tokenId, address, { + ...overrides, + variableOutputs: 1, + }); + const deadline = await wallet.provider.getBlockNumber(); + + process.stdout.write('Depositing ETH\n'); + await exchangeContract.submit.deposit({ + forward: [ethAmount, NativeAssetId], + ...overrides, + }); + process.stdout.write('Depositing Token\n'); + await exchangeContract.submit.deposit({ + forward: [tokenAmount, tokenContract.id], + ...overrides, + }); + process.stdout.write('Add liquidity\n'); + await exchangeContract.submit.add_liquidity(1, deadline + BigInt(1000), { + ...overrides, + variableOutputs: 2, + gasLimit: 100_000_000, + }); +} diff --git a/packages/app/scripts/contracts-init/initializeTokenContract.ts b/packages/app/scripts/contracts-init/initializeTokenContract.ts new file mode 100644 index 00000000..810661f0 --- /dev/null +++ b/packages/app/scripts/contracts-init/initializeTokenContract.ts @@ -0,0 +1,22 @@ +import type { Overrides } from 'fuels'; + +import type { TokenContractAbi } from '../../src/types/contracts'; + +const { MINT_AMOUNT } = process.env; + +export async function initializeTokenContract( + tokenContract: TokenContractAbi, + overrides: Overrides +) { + const mintAmount = BigInt(MINT_AMOUNT || '2000000000000'); + const address = { + value: tokenContract.wallet!.address, + }; + + try { + process.stdout.write('Initialize Token Contract\n'); + await tokenContract.submit.initialize(mintAmount, address, overrides); + } catch (err) { + process.stdout.write('Token Contract already initialized\n'); + } +} diff --git a/packages/app/scripts/contracts-init/loadDockerEnv.ts b/packages/app/scripts/contracts-init/loadDockerEnv.ts new file mode 100644 index 00000000..b4e8cd44 --- /dev/null +++ b/packages/app/scripts/contracts-init/loadDockerEnv.ts @@ -0,0 +1,7 @@ +import dotenv from 'dotenv'; + +const { NODE_ENV } = process.env; + +dotenv.config({ + path: `../../docker/.env${NODE_ENV ? `.${NODE_ENV}` : ''}`, +}); diff --git a/packages/app/scripts/contracts-init/tsconfig.json b/packages/app/scripts/contracts-init/tsconfig.json new file mode 100644 index 00000000..737e8b05 --- /dev/null +++ b/packages/app/scripts/contracts-init/tsconfig.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "lib": ["es2019"], + "declaration": true, + "declarationMap": true, + "baseUrl": "." + }, + "include": ["./index.ts"] +} diff --git a/packages/app/src/systems/Core/hooks/useTokensMethods.ts b/packages/app/src/systems/Core/hooks/useTokensMethods.ts index b82ab368..bc1b9c5a 100644 --- a/packages/app/src/systems/Core/hooks/useTokensMethods.ts +++ b/packages/app/src/systems/Core/hooks/useTokensMethods.ts @@ -1,6 +1,5 @@ import { useMemo } from 'react'; -import { objectId } from '../utils'; import { getOverrides } from '../utils/gas'; import { useWallet } from './useWallet'; @@ -19,15 +18,16 @@ export function useTokenMethods(tokenId: string) { getBalance() { return wallet?.getBalance(tokenId); }, - async queryNetworkFee(amount: bigint) { - return contract.prepareCall.mint_and_transfer_coins(amount, objectId(wallet.address), { + async queryNetworkFee() { + return contract.prepareCall.mint({ variableOutputs: 1, }); }, - mint(amount: bigint, gasLimit: bigint) { - return contract.submit.mint_and_transfer_coins( - amount, - objectId(wallet.address), + async getMintAmount() { + return contract.dryRun.get_mint_amount(); + }, + mint(gasLimit: bigint) { + return contract.submit.mint( getOverrides({ variableOutputs: 1, gasLimit, diff --git a/packages/app/src/systems/Mint/hooks/__mocks__/useMint.ts b/packages/app/src/systems/Mint/hooks/__mocks__/useMint.ts index 747b3f7c..10748364 100644 --- a/packages/app/src/systems/Mint/hooks/__mocks__/useMint.ts +++ b/packages/app/src/systems/Mint/hooks/__mocks__/useMint.ts @@ -1,15 +1,10 @@ import type { Wallet } from 'fuels'; import { TOKEN_ID } from '~/config'; -import { objectId } from '~/systems/Core'; import { getOverrides } from '~/systems/Core/utils/gas'; import { TokenContractAbi__factory } from '~/types/contracts'; -export async function mint(wallet: Wallet, mintAmount: bigint) { +export async function mint(wallet: Wallet) { const contract = TokenContractAbi__factory.connect(TOKEN_ID, wallet); - return contract.submit.mint_and_transfer_coins( - mintAmount, - objectId(wallet.address), - getOverrides({ variableOutputs: 1 }) - ); + return contract.submit.mint(getOverrides({ variableOutputs: 1 })); } diff --git a/packages/app/src/systems/Mint/hooks/useMint.ts b/packages/app/src/systems/Mint/hooks/useMint.ts index e2e4920d..b8977b9e 100644 --- a/packages/app/src/systems/Mint/hooks/useMint.ts +++ b/packages/app/src/systems/Mint/hooks/useMint.ts @@ -1,33 +1,27 @@ import toast from 'react-hot-toast'; -import { useMutation } from 'react-query'; +import { useMutation, useQuery } from 'react-query'; import { useNavigate } from 'react-router-dom'; import { TOKEN_ID } from '~/config'; -import { useTokenMethods, parseUnits, useBalances } from '~/systems/Core'; +import { useTokenMethods, useBalances, ZERO } from '~/systems/Core'; import { useTransactionCost } from '~/systems/Core/hooks/useTransactionCost'; import { Pages } from '~/types'; type UseMintOpts = { - amount: string; - tokenId: string; onSuccess?: () => void; }; -export function useMint(opts: UseMintOpts) { +export function useMint(opts: UseMintOpts = {}) { const methods = useTokenMethods(TOKEN_ID); const navigate = useNavigate(); const balances = useBalances(); - - const txCost = useTransactionCost(['MintPreview--networkFee', opts.amount], () => { - const amount = parseUnits(opts.amount || '0').toBigInt(); - return methods.queryNetworkFee(amount); - }); + const txCost = useTransactionCost(['MintPreview--networkFee'], () => methods.queryNetworkFee()); + const { data: mintAmount } = useQuery(['MintPreview--mintAmount'], () => methods.getMintAmount()); const mutation = useMutation( - async (variables: { amount: string }) => { - const mintAmount = parseUnits(variables.amount).toBigInt(); + async () => { if (!txCost.total) return; - await methods.mint(mintAmount, txCost.total); + await methods.mint(txCost.total); }, { onSuccess: async () => { @@ -39,13 +33,14 @@ export function useMint(opts: UseMintOpts) { } ); - function handleMint(amount: string) { - mutation.mutate({ amount }); + function handleMint() { + mutation.mutate(); } return { ...mutation, txCost, handleMint, + mintAmount: mintAmount || ZERO, }; } diff --git a/packages/app/src/systems/Mint/pages/MintPage.tsx b/packages/app/src/systems/Mint/pages/MintPage.tsx index a56f6d6d..2dc0b3de 100644 --- a/packages/app/src/systems/Mint/pages/MintPage.tsx +++ b/packages/app/src/systems/Mint/pages/MintPage.tsx @@ -1,51 +1,41 @@ -import { useState } from "react"; import { BiCoin } from "react-icons/bi"; import { BsArrowDown } from "react-icons/bs"; -import { TOKEN_ID, MINT_AMOUNT, DECIMAL_UNITS } from "~/config"; import { MainLayout, NetworkFeePreviewItem, + parseToFormattedNumber, PreviewTable, } from "~/systems/Core"; import { useMint } from "~/systems/Mint"; -import { Button, Card, Input, NumberInput } from "~/systems/UI"; +import { Button, Card } from "~/systems/UI"; export function MintPage() { - const [tokenId, setTokenId] = useState(TOKEN_ID); - const [amount, setAmount] = useState(`${MINT_AMOUNT}`); - const mint = useMint({ tokenId, amount }); - const shouldDisableMint = !mint.txCost.total || !!mint.txCost.error; + const mint = useMint(); + const shouldDisableMint = + !mint.txCost.total || !!mint.txCost.error || !mint.mintAmount; + + const getTextButton = () => { + if (!mint.mintAmount) return "Mint is closed!"; + if (!mint.txCost.total) return "Not enough ETH to pay gas fee"; + return "Mint tokens"; + }; return ( - + Mint
- Receive new token types for testing purposes by adding the contract Id - and amount below. -
-
- - + You can mint some DAI once per address only.
-
- - (values.floatValue || 0) <= MINT_AMOUNT} - /> +
+
Amount:
+
+ {parseToFormattedNumber(mint.mintAmount)} +
{!shouldDisableMint && ( <> @@ -64,9 +54,9 @@ export function MintPage() { className="mt-4" isDisabled={shouldDisableMint} isLoading={mint.isLoading} - onPress={() => mint.handleMint(amount)} + onPress={() => mint.handleMint()} > - Mint tokens + {getTextButton()} diff --git a/packages/app/src/systems/Pool/pages/AddLiquidity.test.tsx b/packages/app/src/systems/Pool/pages/AddLiquidity.test.tsx index 54fb1ca9..3a5e27e6 100644 --- a/packages/app/src/systems/Pool/pages/AddLiquidity.test.tsx +++ b/packages/app/src/systems/Pool/pages/AddLiquidity.test.tsx @@ -170,7 +170,7 @@ describe("Add Liquidity", () => { jest.unmock("../hooks/useUserPositions.ts"); await faucet(wallet); - await mint(wallet, MINT_VALUE); + await mint(wallet); const { user } = renderWithRouter(, { route: "/pool/add-liquidity", }); diff --git a/packages/app/src/systems/Swap/pages/SwapPage.test.tsx b/packages/app/src/systems/Swap/pages/SwapPage.test.tsx index 71e9f9c7..02f728eb 100644 --- a/packages/app/src/systems/Swap/pages/SwapPage.test.tsx +++ b/packages/app/src/systems/Swap/pages/SwapPage.test.tsx @@ -8,8 +8,7 @@ import type { Wallet } from "fuels"; import toast from "react-hot-toast"; import { App } from "~/App"; -import { DECIMAL_UNITS } from "~/config"; -import { parseToFormattedNumber, parseUnits } from "~/systems/Core"; +import { parseToFormattedNumber } from "~/systems/Core"; import { createWallet, mockUseWallet, @@ -120,13 +119,12 @@ describe("SwapPage", () => { }); describe("with liquidity created", () => { - const mintValue = parseUnits("2000", DECIMAL_UNITS).toBigInt(); let wallet: Wallet; beforeAll(async () => { wallet = await createAndMockWallet(); await faucet(wallet, 4); - await mint(wallet, mintValue); + await mint(wallet); await addLiquidity(wallet, "0.5", "1000"); }); diff --git a/packages/app/src/types/contracts/TokenContractAbi.d.ts b/packages/app/src/types/contracts/TokenContractAbi.d.ts index dd5306ad..5d6e15bb 100644 --- a/packages/app/src/types/contracts/TokenContractAbi.d.ts +++ b/packages/app/src/types/contracts/TokenContractAbi.d.ts @@ -15,114 +15,145 @@ import type { TransactionResult, } from 'fuels'; -export type ContractIdInput = { value: string }; - -export type ContractId = { value: string }; - export type AddressInput = { value: string }; export type Address = { value: string }; +export type ContractIdInput = { value: string }; + +export type ContractId = { value: string }; + interface TokenContractAbiInterface extends Interface { submit: { - get_balance: FunctionFragment; - get_token_balance: FunctionFragment; + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; - }; - submitResult: { + mint: FunctionFragment; + get_mint_amount: FunctionFragment; get_balance: FunctionFragment; get_token_balance: FunctionFragment; + }; + submitResult: { + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; - }; - dryRun: { + mint: FunctionFragment; + get_mint_amount: FunctionFragment; get_balance: FunctionFragment; get_token_balance: FunctionFragment; + }; + dryRun: { + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; - }; - dryRunResult: { + mint: FunctionFragment; + get_mint_amount: FunctionFragment; get_balance: FunctionFragment; get_token_balance: FunctionFragment; + }; + dryRunResult: { + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; - }; - simulate: { + mint: FunctionFragment; + get_mint_amount: FunctionFragment; get_balance: FunctionFragment; get_token_balance: FunctionFragment; + }; + simulate: { + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; - }; - simulateResult: { + mint: FunctionFragment; + get_mint_amount: FunctionFragment; get_balance: FunctionFragment; get_token_balance: FunctionFragment; + }; + simulateResult: { + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; - }; - prepareCall: { + mint: FunctionFragment; + get_mint_amount: FunctionFragment; get_balance: FunctionFragment; get_token_balance: FunctionFragment; + }; + prepareCall: { + initialize: FunctionFragment; + set_mint_amount: FunctionFragment; mint_coins: FunctionFragment; burn_coins: FunctionFragment; transfer_coins: FunctionFragment; - mint_and_transfer_coins: FunctionFragment; transfer_token_to_output: FunctionFragment; + mint: FunctionFragment; + get_mint_amount: FunctionFragment; + get_balance: FunctionFragment; + get_token_balance: FunctionFragment; }; - encodeFunctionData(functionFragment: 'get_balance', values?: undefined): Uint8Array; - encodeFunctionData(functionFragment: 'get_token_balance', values: [ContractIdInput]): Uint8Array; - encodeFunctionData(functionFragment: 'mint_coins', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'burn_coins', values: [BigNumberish]): Uint8Array; encodeFunctionData( - functionFragment: 'transfer_coins', + functionFragment: 'initialize', values: [BigNumberish, AddressInput] ): Uint8Array; + encodeFunctionData(functionFragment: 'set_mint_amount', values: [BigNumberish]): Uint8Array; + encodeFunctionData(functionFragment: 'mint_coins', values: [BigNumberish]): Uint8Array; + encodeFunctionData(functionFragment: 'burn_coins', values: [BigNumberish]): Uint8Array; encodeFunctionData( - functionFragment: 'mint_and_transfer_coins', + functionFragment: 'transfer_coins', values: [BigNumberish, AddressInput] ): Uint8Array; encodeFunctionData( functionFragment: 'transfer_token_to_output', values: [BigNumberish, ContractIdInput, AddressInput] ): Uint8Array; + encodeFunctionData(functionFragment: 'mint', values?: undefined): Uint8Array; + encodeFunctionData(functionFragment: 'get_mint_amount', values?: undefined): Uint8Array; + encodeFunctionData(functionFragment: 'get_balance', values?: undefined): Uint8Array; + encodeFunctionData(functionFragment: 'get_token_balance', values: [ContractIdInput]): Uint8Array; - decodeFunctionData(functionFragment: 'get_balance', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'get_token_balance', data: BytesLike): DecodedValue; + decodeFunctionData(functionFragment: 'initialize', data: BytesLike): DecodedValue; + decodeFunctionData(functionFragment: 'set_mint_amount', data: BytesLike): DecodedValue; decodeFunctionData(functionFragment: 'mint_coins', data: BytesLike): DecodedValue; decodeFunctionData(functionFragment: 'burn_coins', data: BytesLike): DecodedValue; decodeFunctionData(functionFragment: 'transfer_coins', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'mint_and_transfer_coins', data: BytesLike): DecodedValue; decodeFunctionData(functionFragment: 'transfer_token_to_output', data: BytesLike): DecodedValue; + decodeFunctionData(functionFragment: 'mint', data: BytesLike): DecodedValue; + decodeFunctionData(functionFragment: 'get_mint_amount', data: BytesLike): DecodedValue; + decodeFunctionData(functionFragment: 'get_balance', data: BytesLike): DecodedValue; + decodeFunctionData(functionFragment: 'get_token_balance', data: BytesLike): DecodedValue; } export class TokenContractAbi extends Contract { interface: TokenContractAbiInterface; submit: { - get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + initialize( + mint_amount: BigNumberish, + address: AddressInput, + overrides?: Overrides & { from?: string | Promise } + ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; mint_coins( mint_amount: BigNumberish, @@ -140,26 +171,33 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_mint_amount(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; }; submitResult: { - get_balance( + initialize( + mint_amount: BigNumberish, + address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise>; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } ): Promise>; @@ -179,26 +217,41 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise>; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise>; - transfer_token_to_output( - coins: BigNumberish, + mint( + overrides?: Overrides & { from?: string | Promise } + ): Promise>; + + get_mint_amount( + overrides?: Overrides & { from?: string | Promise } + ): Promise>; + + get_balance( + overrides?: Overrides & { from?: string | Promise } + ): Promise>; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise>; }; dryRun: { - get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + initialize( + mint_amount: BigNumberish, + address: AddressInput, + overrides?: Overrides & { from?: string | Promise } + ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; mint_coins( mint_amount: BigNumberish, @@ -216,24 +269,33 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_mint_amount(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; }; dryRunResult: { - get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + initialize( + mint_amount: BigNumberish, + address: AddressInput, + overrides?: Overrides & { from?: string | Promise } + ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } ): Promise; @@ -253,26 +315,35 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_mint_amount( + overrides?: Overrides & { from?: string | Promise } + ): Promise; + + get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; }; prepareCall: { - get_balance( + initialize( + mint_amount: BigNumberish, + address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } ): Promise; @@ -292,26 +363,41 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint( + overrides?: Overrides & { from?: string | Promise } + ): Promise; + + get_mint_amount( + overrides?: Overrides & { from?: string | Promise } + ): Promise; + + get_balance( + overrides?: Overrides & { from?: string | Promise } + ): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; }; simulate: { - get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + initialize( + mint_amount: BigNumberish, + address: AddressInput, + overrides?: Overrides & { from?: string | Promise } + ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; mint_coins( mint_amount: BigNumberish, @@ -329,24 +415,33 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_mint_amount(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; }; simulateResult: { - get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + initialize( + mint_amount: BigNumberish, + address: AddressInput, + overrides?: Overrides & { from?: string | Promise } + ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } ): Promise; @@ -366,26 +461,37 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_mint_amount( + overrides?: Overrides & { from?: string | Promise } + ): Promise; + + get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; }; - get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + initialize( + mint_amount: BigNumberish, + address: AddressInput, + overrides?: Overrides & { from?: string | Promise } + ): Promise; - get_token_balance( - asset_id: ContractIdInput, + set_mint_amount( + mint_amount: BigNumberish, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; mint_coins( mint_amount: BigNumberish, @@ -403,16 +509,21 @@ export class TokenContractAbi extends Contract { overrides?: Overrides & { from?: string | Promise } ): Promise; - mint_and_transfer_coins( + transfer_token_to_output( coins: BigNumberish, + asset_id: ContractIdInput, address: AddressInput, overrides?: Overrides & { from?: string | Promise } ): Promise; - transfer_token_to_output( - coins: BigNumberish, + mint(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_mint_amount(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_balance(overrides?: Overrides & { from?: string | Promise }): Promise; + + get_token_balance( asset_id: ContractIdInput, - address: AddressInput, overrides?: Overrides & { from?: string | Promise } - ): Promise; + ): Promise; } diff --git a/packages/app/src/types/contracts/factories/TokenContractAbi__factory.ts b/packages/app/src/types/contracts/factories/TokenContractAbi__factory.ts index 38c7adea..f939b67c 100644 --- a/packages/app/src/types/contracts/factories/TokenContractAbi__factory.ts +++ b/packages/app/src/types/contracts/factories/TokenContractAbi__factory.ts @@ -8,22 +8,15 @@ import type { TokenContractAbi, TokenContractAbiInterface } from '../TokenContra const _abi = [ { type: 'function', - inputs: [], - name: 'get_balance', - outputs: [ + inputs: [ { - name: '', + name: 'mint_amount', type: 'u64', components: null, }, - ], - }, - { - type: 'function', - inputs: [ { - name: 'asset_id', - type: 'struct ContractId', + name: 'address', + type: 'struct Address', components: [ { name: 'value', @@ -33,14 +26,32 @@ const _abi = [ ], }, ], - name: 'get_token_balance', + name: 'initialize', outputs: [ { name: '', + type: '()', + components: [], + }, + ], + }, + { + type: 'function', + inputs: [ + { + name: 'mint_amount', type: 'u64', components: null, }, ], + name: 'set_mint_amount', + outputs: [ + { + name: '', + type: '()', + components: [], + }, + ], }, { type: 'function', @@ -115,6 +126,17 @@ const _abi = [ type: 'u64', components: null, }, + { + name: 'asset_id', + type: 'struct ContractId', + components: [ + { + name: 'value', + type: 'b256', + components: null, + }, + ], + }, { name: 'address', type: 'struct Address', @@ -127,7 +149,7 @@ const _abi = [ ], }, ], - name: 'mint_and_transfer_coins', + name: 'transfer_token_to_output', outputs: [ { name: '', @@ -138,26 +160,46 @@ const _abi = [ }, { type: 'function', - inputs: [ + inputs: [], + name: 'mint', + outputs: [ { - name: 'coins', + name: '', + type: '()', + components: [], + }, + ], + }, + { + type: 'function', + inputs: [], + name: 'get_mint_amount', + outputs: [ + { + name: '', type: 'u64', components: null, }, + ], + }, + { + type: 'function', + inputs: [], + name: 'get_balance', + outputs: [ { - name: 'asset_id', - type: 'struct ContractId', - components: [ - { - name: 'value', - type: 'b256', - components: null, - }, - ], + name: '', + type: 'u64', + components: null, }, + ], + }, + { + type: 'function', + inputs: [ { - name: 'address', - type: 'struct Address', + name: 'asset_id', + type: 'struct ContractId', components: [ { name: 'value', @@ -167,12 +209,12 @@ const _abi = [ ], }, ], - name: 'transfer_token_to_output', + name: 'get_token_balance', outputs: [ { name: '', - type: '()', - components: [], + type: 'u64', + components: null, }, ], }, diff --git a/packages/contracts/exchange_contract/src/main.sw b/packages/contracts/exchange_contract/src/main.sw index eb1c66c4..401cddb2 100644 --- a/packages/contracts/exchange_contract/src/main.sw +++ b/packages/contracts/exchange_contract/src/main.sw @@ -16,6 +16,7 @@ use std::{ }; use exchange_abi::{Exchange, PoolInfo, PreviewInfo, PositionInfo, RemoveLiquidityInfo}; +use swayswap_helpers::{get_msg_sender_address_or_panic}; //////////////////////////////////////// // Constants @@ -26,7 +27,7 @@ const ETH_ID = 0x000000000000000000000000000000000000000000000000000000000000000 /// Contract ID of the token on the other side of the pool. /// Modify at compile time for different pool. -const TOKEN_ID = 0x5ab3cc04063b151674a0bbf95fc949b459fcd07425da22077cb72c14f52ee271; +const TOKEN_ID = 0xe3ee9322336a734296dd53afe9b90b1bfc7c716762844669b7895ca9ad438b88; /// Minimum ETH liquidity to open a pool. const MINIMUM_LIQUIDITY = 1; //A more realistic value would be 1000000000; @@ -112,24 +113,6 @@ fn get_output_price(output_amount: u64, input_reserve: u64, output_reserve: u64) } } -/// Return the sender as an Address or panic -fn get_msg_sender_address_or_panic() -> Address { - let result: Result = msg_sender(); - let mut ret = ~Address::from(0x0000000000000000000000000000000000000000000000000000000000000000); - if result.is_err() { - revert(0); - } else { - let unwrapped = result.unwrap(); - if let Sender::Address(v) = unwrapped { - ret = v; - } else { - revert(0); - }; - }; - - ret -} - // //////////////////////////////////////// // // ABI definitions // //////////////////////////////////////// diff --git a/packages/contracts/exchange_contract/tests/harness.rs b/packages/contracts/exchange_contract/tests/harness.rs index 6e1157b4..fe9563e4 100644 --- a/packages/contracts/exchange_contract/tests/harness.rs +++ b/packages/contracts/exchange_contract/tests/harness.rs @@ -102,18 +102,18 @@ async fn exchange_contract() { //////////////////////////////////////////////////////// // Get the contract ID and a handle to it - let wallet_token_amount = 10000; + let wallet_token_amount = 20000; - // Mint some alt tokens + // Initialize token contract token_instance - .mint_coins(wallet_token_amount) + .initialize(wallet_token_amount, address) .call() .await .unwrap(); - // Transfer some alt tokens to the wallet + // Mint some alt tokens token_instance - .transfer_coins(wallet_token_amount, address.clone()) + .mint() .append_variable_outputs(1) .call() .await diff --git a/packages/contracts/swayswap_helpers/src/main.sw b/packages/contracts/swayswap_helpers/src/main.sw index 6f856dc6..d42b85e6 100644 --- a/packages/contracts/swayswap_helpers/src/main.sw +++ b/packages/contracts/swayswap_helpers/src/main.sw @@ -1,6 +1,14 @@ library swayswap_helpers; -use std::{storage::*}; +use std::{ + address::*, + block::*, + chain::auth::*, + context::{*, call_frames::*}, + result::*, + revert::revert, + identity::Identity, +}; pub fn get_b256(key: b256) -> b256 { asm(r1: key, r2) { @@ -17,3 +25,13 @@ pub fn store_b256(key: b256, value: b256) { swwq r1 r2; }; } + +/// Return the sender as an Address or panic +pub fn get_msg_sender_address_or_panic() -> Address { + let sender: Result = msg_sender(); + if let Identity::Address(address) = sender.unwrap() { + address + } else { + revert(0); + } +} diff --git a/packages/contracts/token_abi/src/main.sw b/packages/contracts/token_abi/src/main.sw index 673cca27..70f1fee9 100644 --- a/packages/contracts/token_abi/src/main.sw +++ b/packages/contracts/token_abi/src/main.sw @@ -3,8 +3,14 @@ library token_abi; use std::{address::Address, contract_id::ContractId, token::*}; abi Token { + // Initialize contract + fn initialize(mint_amount: u64, address: Address); + // Set mint amount for each address + fn set_mint_amount(mint_amount: u64); // Get balance of the contract coins fn get_balance() -> u64; + // Return the mint amount + fn get_mint_amount() -> u64; // Get balance of a specified token on contract fn get_token_balance(asset_id: ContractId) -> u64; // Mint token coins @@ -13,9 +19,8 @@ abi Token { fn burn_coins(burn_amount: u64); // Transfer a contract coins to a given output fn transfer_coins(coins: u64, address: Address); - // Mint and transfer coins to a given output - fn mint_and_transfer_coins(coins: u64, address: Address); - // Transfer a specified token from the contract - // to a given output - fn transfer_token_to_output(coins: u64, asset_id: ContractId, recipient: Address); + // Transfer a specified token from the contract to a given output + fn transfer_token_to_output(coins: u64, asset_id: ContractId, address: Address); + // Method called from address to mint coins + fn mint(); } diff --git a/packages/contracts/token_contract/Forc.toml b/packages/contracts/token_contract/Forc.toml index 4486e837..ef5c83dc 100644 --- a/packages/contracts/token_contract/Forc.toml +++ b/packages/contracts/token_contract/Forc.toml @@ -6,3 +6,4 @@ name = "token_contract" [dependencies] token_abi = { path = "../token_abi" } +swayswap_helpers = { path = "../swayswap_helpers" } diff --git a/packages/contracts/token_contract/src/main.sw b/packages/contracts/token_contract/src/main.sw index c1694aee..fe80348c 100644 --- a/packages/contracts/token_contract/src/main.sw +++ b/packages/contracts/token_contract/src/main.sw @@ -1,35 +1,98 @@ contract; -use std::{address::Address, context::balance_of, contract_id::ContractId, token::*}; -use std::context::call_frames::contract_id; +use std::{ + address::*, + assert::require, + context::{*, call_frames::*}, + contract_id::ContractId, + storage::*, + token::*, +}; use token_abi::Token; +use swayswap_helpers::{get_msg_sender_address_or_panic}; + +const ZERO_B256 = 0x0000000000000000000000000000000000000000000000000000000000000000; + +storage { + owner: Address, + mint_amount: u64, + mint_list: StorageMap, +} + +enum Error { + AddressAlreadyMint: (), + CannotReinitialize: (), + MintIsClosed: (), + NotOwner: (), +} + +fn validate_owner() { + let sender = get_msg_sender_address_or_panic(); + require(storage.owner == sender, Error::NotOwner); +} impl Token for Contract { - fn get_balance() -> u64 { - balance_of(contract_id(), contract_id()) + ////////////////////////////////////// + // Owner methods + ////////////////////////////////////// + fn initialize(mint_amount: u64, address: Address) { + require(storage.owner.into() == ZERO_B256, Error::CannotReinitialize); + // Start the next message to be signed + storage.owner = address; + storage.mint_amount = mint_amount; } - fn get_token_balance(asset_id: ContractId) -> u64 { - balance_of(asset_id, contract_id()) + fn set_mint_amount(mint_amount: u64) { + validate_owner(); + storage.mint_amount = mint_amount; } fn mint_coins(mint_amount: u64) { + validate_owner(); mint(mint_amount); } fn burn_coins(burn_amount: u64) { + validate_owner(); burn(burn_amount); } fn transfer_coins(coins: u64, address: Address) { + validate_owner(); transfer_to_output(coins, contract_id(), address); } - fn mint_and_transfer_coins(coins: u64, address: Address) { - mint_to_address(coins, address); - } - fn transfer_token_to_output(coins: u64, asset_id: ContractId, address: Address) { + validate_owner(); transfer_to_output(coins, asset_id, address); } + + ////////////////////////////////////// + // Mint public method + ////////////////////////////////////// + fn mint() { + require(storage.mint_amount > 0, Error::MintIsClosed); + + // Enable a address to mint only once + let sender = get_msg_sender_address_or_panic(); + require(storage.mint_list.get(sender) == false, Error::AddressAlreadyMint); + + storage.mint_list.insert(sender, true); + mint_to_address(storage.mint_amount, sender); + } + + ////////////////////////////////////// + // Read-Only methods + ////////////////////////////////////// + fn get_mint_amount() -> u64 { + storage.mint_amount + } + + fn get_balance() -> u64 { + balance_of(contract_id(), contract_id()) + } + + fn get_token_balance(asset_id: ContractId) -> u64 { + balance_of(asset_id, contract_id()) + } } diff --git a/packages/contracts/token_contract/tests/harness.rs b/packages/contracts/token_contract/tests/harness.rs index e968e5ad..cc966105 100644 --- a/packages/contracts/token_contract/tests/harness.rs +++ b/packages/contracts/token_contract/tests/harness.rs @@ -1,5 +1,5 @@ use fuel_tx::{AssetId, ContractId}; -use fuels::prelude::*; +use fuels::{prelude::*}; use fuels_abigen_macro::abigen; /////////////////////////////// @@ -13,7 +13,15 @@ abigen!( #[tokio::test] async fn token_contract() { // default initial amount 1000000000 - let wallet = launch_provider_and_get_single_wallet().await; + let initial_amount = 1000000000; + let wallets = launch_provider_and_get_wallets(WalletsConfig { + num_wallets: 3, + coins_per_wallet: 1, + coin_amount: initial_amount + }).await; + let wallet_owner = wallets.get(0).unwrap(); + let wallet_mint1 = wallets.get(1).unwrap(); + let wallet_mint2 = wallets.get(2).unwrap(); //////////////////////////////////////////////////////// // Setup contracts @@ -21,12 +29,12 @@ async fn token_contract() { let token_contract_id = Contract::deploy( "../token_contract/out/debug/token_contract.bin", - &wallet, + &wallet_owner, TxParameters::default(), ) .await .unwrap(); - let token_instance = TestToken::new(token_contract_id.to_string(), wallet.clone()); + let token_instance = TestToken::new(token_contract_id.to_string(), wallet_owner.clone()); //////////////////////////////////////////////////////// // Test Token Contract @@ -36,8 +44,49 @@ async fn token_contract() { let token_mint_amount = 10000; // Amount of tokens given to the wallet let wallet_token_amount = 1000; - // Amount of tokens given to the wallet - let final_wallet_token_amount = 2000; + + // Initialize contract + token_instance + .initialize(token_mint_amount, wallet_owner.address()) + .call() + .await + .unwrap(); + + // Contract can be initialized only once + let is_error = token_instance + .initialize(token_mint_amount, wallet_owner.address()) + .call() + .await + .is_err(); + assert!(is_error); + + // Verify the mint amount + let mint_amount_contract = token_instance + .get_mint_amount() + .call() + .await + .unwrap(); + assert_eq!(mint_amount_contract.value, token_mint_amount); + + // Verify update mint amount + token_instance + .set_mint_amount(1) + .call() + .await + .unwrap(); + let mint_amount_contract = token_instance + .get_mint_amount() + .call() + .await + .unwrap(); + assert_eq!(mint_amount_contract.value, 1); + + // Update mint amount to the original value + token_instance + .set_mint_amount(token_mint_amount) + .call() + .await + .unwrap(); // Mint some alt tokens token_instance @@ -51,7 +100,7 @@ async fn token_contract() { assert_eq!(result.value, token_mint_amount); // Transfer tokens to the wallet - let address = wallet.address(); + let address = wallet_owner.address(); token_instance .transfer_coins(wallet_token_amount, address.clone()) .append_variable_outputs(1) @@ -78,33 +127,87 @@ async fn token_contract() { // Test mint and transfer to address //////////////////////////////////////////////////////// + let token_mint1_instance = TestToken::new(token_contract_id.to_string(), wallet_mint1.clone()); // Mint and transfer some alt tokens to the wallet - let address = wallet.address(); - token_instance - .mint_and_transfer_coins(wallet_token_amount, address.clone()) + token_mint1_instance + .mint() .append_variable_outputs(1) .call() .await .unwrap(); - - // As we mint and transfer the contract balance should be 0 - let result = token_instance.get_balance().call().await.unwrap(); - assert_eq!(result.value, 0); + // Mint can be called only once + let is_error = token_mint1_instance + .mint() + .append_variable_outputs(1) + .call() + .await + .is_err(); + assert!(is_error); // Inspect the wallet for alt tokens let alt_token_id = AssetId::from(*token_contract_id.clone()); - let alt_token_balance = wallet + let alt_token_balance = wallet_mint1 .get_asset_balance(&alt_token_id) .await .unwrap(); // The wallet shall received the tokens minted - assert_eq!(alt_token_balance, final_wallet_token_amount); + assert_eq!(alt_token_balance, token_mint_amount); + + // Other wallet should be able to mint tokens + let token_mint2_instance = TestToken::new(token_contract_id.to_string(), wallet_mint2.clone()); + token_mint2_instance + .mint() + .append_variable_outputs(1) + .call() + .await + .unwrap(); + + // Inspect the wallet for alt tokens + let alt_token_balance2 = wallet_mint2 + .get_asset_balance(&alt_token_id) + .await + .unwrap(); + // The wallet shall received the tokens minted + assert_eq!(alt_token_balance2, token_mint_amount); + + // As we mint and transfer the contract balance should be 0 + let result = token_instance.get_balance().call().await.unwrap(); + assert_eq!(result.value, 0); + + //////////////////////////////////////////////////////// + // Check only owner can call contract + //////////////////////////////////////////////////////// + + let is_error = token_mint1_instance + .burn_coins(1) + .call() + .await + .is_err(); + assert!(is_error); + let is_error = token_mint1_instance + .mint_coins(1) + .call() + .await + .is_err(); + assert!(is_error); + let is_error = token_mint1_instance + .set_mint_amount(1) + .call() + .await + .is_err(); + assert!(is_error); + let is_error = token_mint1_instance + .transfer_token_to_output(1, token_contract_id, wallet_mint2.address()) + .call() + .await + .is_err(); + assert!(is_error); //////////////////////////////////////////////////////// // Deposit and transfer ETH on the contract //////////////////////////////////////////////////////// - let wallet_native_balance_before = wallet + let wallet_native_balance_before = wallet_owner .get_asset_balance(&NATIVE_ASSET_ID) .await .unwrap(); @@ -123,7 +226,7 @@ async fn token_contract() { assert_eq!(contract_native_token_balance.value, send_native_token_amount); // Check user balance didn't has the sent native tokens - let wallet_native_balance_after = wallet + let wallet_native_balance_after = wallet_owner .get_asset_balance(&NATIVE_ASSET_ID) .await .unwrap(); @@ -134,13 +237,13 @@ async fn token_contract() { .transfer_token_to_output( send_native_token_amount, ContractId::from(*NATIVE_ASSET_ID), - wallet.address() + wallet_owner.address() ) .append_variable_outputs(1) .call() .await .unwrap(); - let wallet_native_balance_after = wallet + let wallet_native_balance_after = wallet_owner .get_asset_balance(&NATIVE_ASSET_ID) .await .unwrap(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26ae4b1e..de01696e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,7 @@ importers: react-use: ^17.4.0 spinners-react: ^1.0.7 tailwindcss: ^3.0.24 + ts-node: ^10.8.1 typescript: ^4.7.3 url-join-ts: ^1.0.5 vite: ^2.9.10 @@ -207,7 +208,8 @@ importers: http-server: 14.1.1 postcss: 8.4.14 postcss-import: 14.1.0_postcss@8.4.14 - tailwindcss: 3.1.2 + tailwindcss: 3.1.2_ts-node@10.8.1 + ts-node: 10.8.1_f5eqjuxkorpjvs4z7mviievvou typescript: 4.7.3 vite: 2.9.12 @@ -1605,7 +1607,6 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/trace-mapping': 0.3.9 - dev: true /@cush/relative/1.0.0: resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==} @@ -2737,7 +2738,6 @@ packages: /@jridgewell/resolve-uri/3.0.7: resolution: {integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array/1.1.1: resolution: {integrity: sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==} @@ -2746,7 +2746,6 @@ packages: /@jridgewell/sourcemap-codec/1.4.13: resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==} - dev: true /@jridgewell/trace-mapping/0.3.13: resolution: {integrity: sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==} @@ -2760,7 +2759,6 @@ packages: dependencies: '@jridgewell/resolve-uri': 3.0.7 '@jridgewell/sourcemap-codec': 1.4.13 - dev: true /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -3784,7 +3782,7 @@ packages: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 - tailwindcss: 3.1.2 + tailwindcss: 3.1.2_ts-node@10.8.1 dev: false /@testing-library/dom/8.13.0: @@ -3868,19 +3866,15 @@ packages: /@tsconfig/node10/1.0.8: resolution: {integrity: sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==} - dev: true /@tsconfig/node12/1.0.9: resolution: {integrity: sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==} - dev: true /@tsconfig/node14/1.0.1: resolution: {integrity: sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==} - dev: true /@tsconfig/node16/1.0.2: resolution: {integrity: sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==} - dev: true /@types/aria-query/4.2.2: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} @@ -4031,7 +4025,6 @@ packages: /@types/node/17.0.41: resolution: {integrity: sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==} - dev: true /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -4428,7 +4421,6 @@ packages: acorn: 7.4.1 acorn-walk: 7.2.0 xtend: 4.0.2 - dev: true /acorn-walk/6.2.0: resolution: {integrity: sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==} @@ -4438,12 +4430,10 @@ packages: /acorn-walk/7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} - dev: true /acorn-walk/8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} - dev: true /acorn/6.4.2: resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} @@ -4455,7 +4445,6 @@ packages: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /acorn/8.7.1: resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==} @@ -4567,7 +4556,6 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true /arch/2.2.0: resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} @@ -4575,11 +4563,9 @@ packages: /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true /arg/5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: true /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -5050,7 +5036,6 @@ packages: /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: true /blob-util/2.0.2: resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} @@ -5223,7 +5208,6 @@ packages: /camelcase-css/2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - dev: true /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} @@ -5306,7 +5290,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.2 - dev: true /ci-info/2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -5577,7 +5560,6 @@ packages: /create-require/1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true /cross-fetch/3.1.5: resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} @@ -5643,7 +5625,6 @@ packages: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true - dev: true /cssom/0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} @@ -5882,7 +5863,6 @@ packages: /defined/1.0.0: resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} - dev: true /delayed-stream/1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -5913,11 +5893,9 @@ packages: acorn-node: 1.8.2 defined: 1.0.0 minimist: 1.2.6 - dev: true /didyoumean/1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true /diff-sequences/25.2.6: resolution: {integrity: sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==} @@ -5935,7 +5913,6 @@ packages: /diff/4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - dev: true /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} @@ -5945,7 +5922,6 @@ packages: /dlv/1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: true /doctrine/2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} @@ -7454,7 +7430,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /fuels/0.0.0-master-3caba861: @@ -8125,7 +8100,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: true /is-boolean-object/1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} @@ -9666,7 +9640,6 @@ packages: /lilconfig/2.0.5: resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==} engines: {node: '>=10'} - dev: true /lines-and-columns/1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -9882,7 +9855,6 @@ packages: /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true /makeerror/1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -10104,7 +10076,6 @@ packages: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: true /nanomatch/1.2.13: resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} @@ -10190,7 +10161,6 @@ packages: /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dev: true /normalize-range/0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} @@ -10258,7 +10228,6 @@ packages: /object-hash/3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - dev: true /object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} @@ -10553,7 +10522,6 @@ packages: /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true /picomatch/2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -10574,7 +10542,6 @@ packages: /pify/2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: true /pify/3.0.0: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} @@ -10632,7 +10599,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.0 - dev: true /postcss-js/4.0.0_postcss@8.4.14: resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} @@ -10642,7 +10608,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.14 - dev: true /postcss-load-config/3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} @@ -10660,7 +10625,7 @@ packages: yaml: 1.10.2 dev: true - /postcss-load-config/3.1.4_postcss@8.4.14: + /postcss-load-config/3.1.4_apxnowcr5uhxb4jlsbpuejnlvi: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} peerDependencies: @@ -10674,8 +10639,8 @@ packages: dependencies: lilconfig: 2.0.5 postcss: 8.4.14 + ts-node: 10.8.1_f5eqjuxkorpjvs4z7mviievvou yaml: 1.10.2 - dev: true /postcss-load-config/3.1.4_ts-node@10.8.1: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} @@ -10702,7 +10667,6 @@ packages: dependencies: postcss: 8.4.14 postcss-selector-parser: 6.0.10 - dev: true /postcss-selector-parser/6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} @@ -10710,11 +10674,9 @@ packages: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - dev: true /postcss-value-parser/4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: true /postcss/8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} @@ -10723,7 +10685,6 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true /prelude-ls/1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} @@ -10849,7 +10810,6 @@ packages: /quick-lru/5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} - dev: true /ramda/0.26.1: resolution: {integrity: sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==} @@ -11102,13 +11062,11 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: false /read-cache/1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 - dev: true /read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -11143,7 +11101,6 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: true /realpath-native/2.0.0: resolution: {integrity: sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==} @@ -11499,7 +11456,6 @@ packages: hasBin: true optionalDependencies: fsevents: 2.3.2 - dev: true /rsvp/4.8.5: resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} @@ -11792,7 +11748,6 @@ packages: /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: true /source-map-resolve/0.5.3: resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} @@ -12218,7 +12173,7 @@ packages: string-width: 3.1.0 dev: true - /tailwindcss/3.1.2: + /tailwindcss/3.1.2_ts-node@10.8.1: resolution: {integrity: sha512-yJ6L5s1U5AeS5g7HHy212zdQfjwD426FBfm59pet/JsyneuZuD4C2W7PpJEg4ppisiB21uLqtNagv8KXury3+Q==} engines: {node: '>=12.13.0'} hasBin: true @@ -12239,7 +12194,7 @@ packages: postcss: 8.4.14 postcss-import: 14.1.0_postcss@8.4.14 postcss-js: 4.0.0_postcss@8.4.14 - postcss-load-config: 3.1.4_postcss@8.4.14 + postcss-load-config: 3.1.4_apxnowcr5uhxb4jlsbpuejnlvi postcss-nested: 5.0.6_postcss@8.4.14 postcss-selector-parser: 6.0.10 postcss-value-parser: 4.2.0 @@ -12247,7 +12202,6 @@ packages: resolve: 1.22.0 transitivePeerDependencies: - ts-node - dev: true /terminal-link/2.1.1: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} @@ -12522,6 +12476,36 @@ packages: yargs-parser: 20.2.9 dev: true + /ts-node/10.8.1_f5eqjuxkorpjvs4z7mviievvou: + resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.8 + '@tsconfig/node12': 1.0.9 + '@tsconfig/node14': 1.0.1 + '@tsconfig/node16': 1.0.2 + '@types/node': 17.0.41 + acorn: 8.7.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.7.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + /ts-node/10.8.1_vslk2fq76uzvudesky66pvr6g4: resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==} hasBin: true @@ -13133,7 +13117,6 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} - dev: true /uuid/3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} @@ -13148,7 +13131,6 @@ packages: /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true /v8-compile-cache/2.3.0: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} @@ -13223,7 +13205,6 @@ packages: rollup: 2.75.6 optionalDependencies: fsevents: 2.3.2 - dev: true /w3c-hr-time/1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} @@ -13259,7 +13240,7 @@ packages: dev: true /webidl-conversions/3.0.1: - resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=} + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false /webidl-conversions/4.0.2: @@ -13475,7 +13456,6 @@ packages: /xtend/4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - dev: true /y18n/4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -13492,7 +13472,6 @@ packages: /yaml/1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - dev: true /yaml/2.1.1: resolution: {integrity: sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==} @@ -13557,4 +13536,3 @@ packages: /yn/3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} - dev: true diff --git a/swayswap.config.ts b/swayswap.config.ts index 137ffa42..1977c2fc 100644 --- a/swayswap.config.ts +++ b/swayswap.config.ts @@ -1,8 +1,10 @@ import dotenv from 'dotenv'; import { createConfig, replaceEventOnEnv } from 'swayswap-scripts'; +const { NODE_ENV, OUTPUT_ENV } = process.env; + function getEnvName() { - if (process.env.NODE_ENV === 'test') { + if (NODE_ENV === 'test') { return '.env.test'; } return '.env'; @@ -28,6 +30,6 @@ export default createConfig({ }, ], onSuccess: (event) => { - replaceEventOnEnv(`./packages/app/${getEnvName()}`, event); + replaceEventOnEnv(`./packages/app/${OUTPUT_ENV || getEnvName()}`, event); }, });