Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/soroswap/frontend into fix/…
Browse files Browse the repository at this point in the history
…ExactOutputSCA
  • Loading branch information
MattPoblete committed Sep 2, 2024
2 parents f6a59fd + b918dcc commit bcbc296
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 73 deletions.
57 changes: 29 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,49 @@ Before you begin, ensure you have met the following requirements:

## 🛠 Setting Up Soroswap 🛠

1. Clone the Repository
### 1. Clone the Repository

```bash

git clone https://github.com/soroswap/frontend.git
cd frontend
```

2. Set Up Environment Variables
### 2.Set Up Environment Variables

Copy the .env.example file to create a new .env file:
Copy the .env.example file to create a new .env file:

```bash
cp .env.local.example .env
```
```bash
cp .env.local.example .env
```
Edit the `.env` file and provide the following variables:
```md
NEXT_PUBLIC_BACKEND_URL=http://localhost:8010 // If you are following the instructions in `https://github.com/soroswap/core`
NEXT_PUBLIC_SOROSWAP_BACKEND_URL=http://localhost:8000// Your local soroswap backend url
NEXT_PUBLIC_SOROSWAP_BACKEND_ENABLED= false // Enables or disables the soroswap backend
NEXT_PUBLIC_DEFAULT_NETWORK= standalone // The default network to connect
NEXT_PUBLIC_AGGREGATOR_ENABLED= false // Enables or disables the aggregator
NEXT_PUBLIC_SOROSWAP_BACKEND_API_KEY= BACKEND_API_KEY // The API key to autenthicate in the soroswap backend
NEXT_PUBLIC_TRUSTLINE_WALLET_PUBLIC_KEY= STELLAR_PUBLIC_KEY// The public key of the trustline wallet
NEXT_PUBLIC_TEST_TOKENS_ADMIN_SECRET_KEY= STELLAR_SECRET_KEY // The secret key of the test tokens admin
```
Hints:
The `NEXT_PUBLIC_BACKEND_URL` should serve:
- the list of known tokens
- the SoroswapFactory address
- the SoroswapRouter address

Now, edit the `.env` file and provide the `NEXT_PUBLIC_BACKEND_URL`, `NEXT_PUBLIC_SOROSWAP_BACKEND_API_KEY` and `NEXT_PUBLIC_TEST_TOKENS_ADMIN_SECRET_KEY` variables.
This will tell the frontend where to look for:
The `NEXT_PUBLIC_TEST_TOKENS_ADMIN_SECRET_KEY` should be the same as the one that deployed the tokens in the `core` repository.

- the list of known tokens
- the SoroswapFactory address
- the SoroswapRouter address
- the admin key for token minting
To enable or disable features like the `Soroswap backend` or the `aggregator`, switch the `NEXT_PUBLIC_SOROSWAP_BACKEND_ENABLED` and `NEXT_PUBLIC_AGGREGATOR_ENABLED` variables to `true` or `false`.

If you are following the instructions in `https://github.com/soroswap/core` in order to deploy the smart contacts in your local environment and serve the API. you should have:
```bash
NEXT_PUBLIC_BACKEND_URL=http://localhost:8010
```
If you don't want to use the backend, you should also set the following variable:
```bash
NEXT_PUBLIC_SOROSWAP_BACKEND_ENABLED=false
```
Also, the variable `NEXT_PUBLIC_TEST_TOKENS_ADMIN_SECRET_KEY` should be the same as the one that deployed the tokens in the `core` repository.
Then, when you are ready for production, you can take Futurenet Contracts information from `https://api.soroswap.finance` and use the production env file:

If you are ready for production, you can take Futurenet Contracts information from `https://api.soroswap.finance` and just do
```bash
cp .env.production.example .env
```
```bash
cp .env.production.example .env
```

❗️❗️ Note that some Futurenet RPC's might not have the same version, so we recomend you to connect to a local quickstart node following the instructions in `https://github.com/soroswap/core`; and setting up your Freighter Wallet as in step 6.
> [!IMPORTANT] Note that some Futurenet RPC's might not have the same version, so we strongly recomend you to connect to a local quickstart node following the instructions in `https://github.com/soroswap/core`; and setting up your Freighter Wallet as in step 6.
1. Start Docker

Expand Down
69 changes: 54 additions & 15 deletions cypress/e2e/flows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,27 +133,19 @@ describe('Select tokens & input amount', () => {
describe('Input & output amount validation', () => {
it('should type an input amount & wait for output amount', () => {
cy.visit('/swap');
//Select input asset
/* cy.get('[data-testid="swap__input__panel"]').within(() => {
cy.get('[data-testid="swap__token__select"]').click();
});
cy.get('[data-testid="currency__list__XLM"]').click();
*/
//Select output asset
cy.get('[data-testid="swap__output__panel"]').within(() => {
cy.get('[data-testid="swap__token__select"]').click();
});
cy.get('[data-testid="token-search-input"]').type('ngnt');
cy.get('[data-testid="currency__list__NGNT"]').click();

cy.get('[data-testid="token-search-input"]').type('usdc');
cy.get('[data-testid="currency__list__USDC"]').click();

//Input amount
cy.get('[data-testid="swap__input__panel"]').within(() => {
cy.get('.token-amount-input').type('1');
});
//await for calcs
cy.wait(5000);
cy.screenshot()
//Get the output amount
cy.get('[data-testid="swap-output-input-panel"]').invoke('val').as('outputAmount');
//Get the input amount
Expand All @@ -168,25 +160,72 @@ describe('Input & output amount validation', () => {
cy.get('[data-testid="swap__input__panel"]').within(() => {
cy.get('[data-testid="swap__token__select"]').click();
});
cy.get('[data-testid="token-search-input"]').type('ngnt');
cy.get('[data-testid="currency__list__NGNT"]').click();
cy.get('[data-testid="token-search-input"]').type('usdc');
cy.get('[data-testid="currency__list__USDC"]').click();
//Input amount
cy.get('[data-testid="swap__output__panel"]').within(() => {
cy.get('.token-amount-input').type('{backspace}');
cy.get('.token-amount-input').type('{backspace}');
cy.get('.token-amount-input').type('1');
});
cy.wait(2500);
cy.screenshot()
cy.get('[data-testid="swap-input-input-panel"]').invoke('val').then((inputAmount: any)=>{
const belowOutput = Math.floor(parseFloat(outputAmount) * 0.9);
const aboveOutput = Math.ceil(parseFloat(outputAmount) * 1.1);
const belowOutput = Math.floor(parseFloat(outputAmount) * 0.5);
const aboveOutput = Math.ceil(parseFloat(outputAmount) * 1.5);
expect(parseFloat(inputAmount)).within(belowOutput, aboveOutput)
})
})

})
});

describe('Slippage tolerance config', ()=>{
it('should change slippage tolerance', ()=>{
cy.visit('/swap');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').click();
cy.get('[data-testid="slippage-input"]').type('1.05');
cy.get('[data-testid="max-slippage-settings"]').contains('1.05%');
})
it('Show display an alert if slippage is too high', ()=>{
cy.visit('/swap');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').click();
cy.get('[data-testid="slippage-input"]').type('10');
cy.get('[data-testid="max-slippage-settings"]').contains('10%');
cy.get('[data-testid="slippage-alert"]').should('exist');
cy.get('[data-testid="slippage-alert-too-high"]').should('exist');
})
it('Show display an alert if slippage is too low', ()=>{
cy.visit('/swap');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').click();
cy.get('[data-testid="slippage-input"]').type('0.01');
cy.get('[data-testid="max-slippage-settings"]').contains('0.01%');
cy.get('[data-testid="slippage-alert"]').should('exist');
cy.get('[data-testid="slippage-alert-too-low"]').should('exist');
})
it('should keep the slippage tolerance after closing the settings', ()=>{
cy.visit('/swap');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').click();
cy.get('[data-testid="slippage-input"]').type('1.05');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').should('not.exist');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').should('exist')
cy.get('[data-testid="max-slippage-settings"]').contains('1.05%');
})
it('Should set the slippage tolerance to auto when pressing "auto" button', ()=>{
cy.visit('/swap');
cy.get('[data-testid="open-settings-dialog-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').click();
cy.get('[data-testid="slippage-input"]').type('1.05');
cy.get('[data-testid="max-slippage-settings"]').contains('1.05%');
cy.get('[data-testid="slippage-auto-button"]').click();
cy.get('[data-testid="max-slippage-settings"]').contains('Auto');
})
})
// Navigation flow
describe('Navigation flow', () => {
it('should render the navbar', () => {
Expand Down
61 changes: 43 additions & 18 deletions src/components/CopyTxHash/CopyTxHash.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,62 @@ const getExplorerUrl = ({ chain, txHash }: { chain: WalletChain; txHash: string
}
};

enum ExplorerType {
STELLAR_EXPERT = 'STELLAR_EXPERT',
STELLAR_CHAIN = 'STELLAR_CHAIN',
}

interface ExplorerLinks {
stellarExpert: string;
stellarChain: string;
}

const CopyTxHash = ({ txHash }: { txHash: string }) => {
const { notify } = useNotification();

const sorobanContext = useSorobanReact();

const [explorerLink, setExplorerLink] = useState<string | undefined>(undefined);
const activeChain = sorobanContext?.activeChain;

useEffect(() => {
if (!sorobanContext) return;
const [explorersLinks, setExplorersLinks] = useState<ExplorerLinks | undefined>(undefined);

const activeChain = sorobanContext.activeChain;

if (!activeChain) return;
useEffect(() => {
if (!sorobanContext || !activeChain) return;

if (activeChain.name === testnet.name || activeChain.name === mainnet.name) {
setExplorerLink(getExplorerUrl({ chain: activeChain, txHash }));
if (activeChain.name === testnet.name) {
setExplorersLinks({
stellarExpert: `https://stellar.expert/explorer/testnet/tx/${txHash}`,
stellarChain: `https://testnet.stellarchain.io/transactions/${txHash}`,
});
}
}, [sorobanContext, txHash]);

const handleClickViewOnExplorer = () => {
if (!explorerLink) return;
if (activeChain.name === mainnet.name) {
setExplorersLinks({
stellarExpert: `https://stellar.expert/explorer/public/tx/${txHash}`,
stellarChain: `https://stellarchain.io/transactions/${txHash}`,
});
}
}, [sorobanContext, txHash]);

window.open(explorerLink, '_blank');
};
return (
<Box display="flex" alignItems="center" flexDirection="column">
<Box display="flex" alignItems="center" flexDirection="column" sx={{ mt: 1 }}>
{(explorersLinks?.stellarChain && explorersLinks.stellarExpert) && (
<>
<LabelSmall style={{ cursor: 'pointer' }}>
<a href={explorersLinks?.stellarExpert}
target='_blank'>
View on Stellar.Expert
</a>
</LabelSmall>
<LabelSmall style={{ cursor: 'pointer' }}>
<a href={explorersLinks?.stellarChain}
target='_blank'>
View on StellarChain.io
</a>
</LabelSmall>
</>
)}
<CopyToClipboard
text={txHash}
onCopy={() =>
Expand All @@ -61,11 +91,6 @@ const CopyTxHash = ({ txHash }: { txHash: string }) => {
<Clipboard color="white" size="16px" />
</Row>
</CopyToClipboard>
{explorerLink && (
<LabelSmall style={{ cursor: 'pointer' }} onClick={handleClickViewOnExplorer}>
View on explorer
</LabelSmall>
)}
</Box>
);
};
Expand Down
25 changes: 13 additions & 12 deletions src/components/Settings/MaxSlippageSettings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,16 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: nu

function setCustomSlippage() {
// When switching to custom slippage, use `auto` value as a default.
setUserSlippageTolerance(autoSlippage);
selectSlippageInput();
}

const removeTrailingZeroes = (num: number) => {
return num
const removeTrailingZeroes = (num: number | SlippageTolerance.Auto) => {
if (num === SlippageTolerance.Auto) return;
const parsedNum = num
.toFixed(2)
.toString()
.replace(/0{1,}$/, '');
return parsedNum[parsedNum.length - 1] === '.' ? parsedNum.slice(0, -1) : parsedNum;
};

useEffect(function () {
Expand Down Expand Up @@ -139,8 +140,8 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: nu
</Row>
}
button={
<Typography color={theme.palette.primary.main}>
{isAuto ? <>Auto</> : `${removeTrailingZeroes(userSlippageTolerance)}%`}
<Typography>
{isAuto ? 'Auto' : `${removeTrailingZeroes(userSlippageTolerance)}%`}
</Typography>
}
>
Expand All @@ -154,7 +155,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: nu
}}
isActive={isAuto}
>
<Typography color={theme.palette.primary.main} component="div">
<Typography color={theme.palette.primary.main} component="div" data-testid='slippage-auto-button'>
Auto
</Typography>
</Option>
Expand All @@ -173,26 +174,26 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: nu
onChange={(e) => parseSlippageInput(e.target.value)}
onBlur={() => {
// When the input field is blurred, reset the input field to the default value
setSlippageInput(DEFAULT_SLIPPAGE_INPUT_VALUE);
setSlippageError(false);
//setSlippageInput(DEFAULT_SLIPPAGE_INPUT_VALUE);
//setSlippageError(false);
}}
onFocus={setCustomSlippage}
type="number"
type="text"
step="0.1"
/>
<Typography color={theme.palette.primary.main}>%</Typography>
</InputContainer>
</RowBetween>
{tooLow || tooHigh ? (
<RowBetween gap="md">
<Alert severity="warning">
<Alert severity="warning" data-testid='slippage-alert'>
{tooLow ? (
<div>
<div data-testid='slippage-alert-too-low'>
Slippage below {MINIMUM_RECOMMENDED_SLIPPAGE.toFixed(2)}% may result in a failed
transaction
</div>
) : (
<div>Your transaction may be frontrun and result in an unfavorable trade.</div>
<div data-testid='slippage-alert-too-high'>Your transaction may be frontrun and result in an unfavorable trade.</div>
)}
</Alert>
</RowBetween>
Expand Down

0 comments on commit bcbc296

Please sign in to comment.