Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add alpaca #415

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,845 changes: 1,845 additions & 0 deletions src/abi/alpaca/GetterFacet.json

Large diffs are not rendered by default.

597 changes: 597 additions & 0 deletions src/abi/alpaca/LiquidityFacet.json

Large diffs are not rendered by default.

568 changes: 568 additions & 0 deletions src/abi/alpaca/PoolRouter.json

Large diffs are not rendered by default.

158 changes: 158 additions & 0 deletions src/dex/alpaca/alpaca-e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/* eslint-disable no-console */
import dotenv from 'dotenv';
dotenv.config();

import { testE2E } from '../../../tests/utils-e2e';
import {
Tokens,
Holders,
NativeTokenSymbols,
} from '../../../tests/constants-e2e';
import { Network, ContractMethod, SwapSide } from '../../constants';
import { StaticJsonRpcProvider } from '@ethersproject/providers';
import { generateConfig } from '../../config';

/*
README
======

This test script should add e2e tests for Alpaca. The tests
should cover as many cases as possible. Most of the DEXes follow
the following test structure:
- DexName
- ForkName + Network
- ContractMethod
- ETH -> Token swap
- Token -> ETH swap
- Token -> Token swap

The template already enumerates the basic structure which involves
testing simpleSwap, multiSwap, megaSwap contract methods for
ETH <> TOKEN and TOKEN <> TOKEN swaps. You should replace tokenA and
tokenB with any two highly liquid tokens on Alpaca for the tests
to work. If the tokens that you would like to use are not defined in
Tokens or Holders map, you can update the './tests/constants-e2e'

Other than the standard cases that are already added by the template
it is highly recommended to add test cases which could be specific
to testing Alpaca (Eg. Tests based on poolType, special tokens,
etc).

You can run this individual test script by running:
`npx jest src/dex/<dex-name>/<dex-name>-e2e.test.ts`

e2e tests use the Tenderly fork api. Please add the following to your
.env file:
TENDERLY_TOKEN=Find this under Account>Settings>Authorization.
TENDERLY_ACCOUNT_ID=Your Tenderly account name.
TENDERLY_PROJECT=Name of a Tenderly project you have created in your
dashboard.

(This comment should be removed from the final implementation)
*/

function testForNetwork(
network: Network,
dexKey: string,
tokenASymbol: string,
tokenBSymbol: string,
tokenAAmount: string,
tokenBAmount: string,
nativeTokenAmount: string,
) {
const provider = new StaticJsonRpcProvider(
generateConfig(network).privateHttpProvider,
network,
);
const tokens = Tokens[network];
const holders = Holders[network];
const nativeTokenSymbol = NativeTokenSymbols[network];

// TODO: Add any direct swap contractMethod name if it exists
const sideToContractMethods = new Map([
[
SwapSide.SELL,
[
ContractMethod.simpleSwap,
ContractMethod.multiSwap,
ContractMethod.megaSwap,
],
],
]);

describe(`${network}`, () => {
sideToContractMethods.forEach((contractMethods, side) =>
describe(`${side}`, () => {
contractMethods.forEach((contractMethod: ContractMethod) => {
describe(`${contractMethod}`, () => {
it(`${nativeTokenSymbol} -> ${tokenASymbol}`, async () => {
await testE2E(
tokens[nativeTokenSymbol],
tokens[tokenASymbol],
holders[nativeTokenSymbol],
side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount,
side,
dexKey,
contractMethod,
network,
provider,
);
});
it(`${tokenASymbol} -> ${nativeTokenSymbol}`, async () => {
await testE2E(
tokens[tokenASymbol],
tokens[nativeTokenSymbol],
holders[tokenASymbol],
side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount,
side,
dexKey,
contractMethod,
network,
provider,
);
});
it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => {
await testE2E(
tokens[tokenASymbol],
tokens[tokenBSymbol],
holders[tokenASymbol],
side === SwapSide.SELL ? tokenAAmount : tokenBAmount,
side,
dexKey,
contractMethod,
network,
provider,
);
});
});
});
}),
);
});
}

describe('Alpaca E2E', () => {
const dexKey = 'Alpaca';

describe('Alpaca BSC', () => {
const network = Network.BSC;

// TODO: Modify the tokenASymbol, tokenBSymbol, tokenAAmount;
const tokenASymbol: string = 'USDT';
const tokenBSymbol: string = 'USDC';

const tokenAAmount: string = '1000000000000000000';
const tokenBAmount: string = '1000000000000000000';
const nativeTokenAmount = '1000000000000000000';

testForNetwork(
network,
dexKey,
tokenASymbol,
tokenBSymbol,
tokenAAmount,
tokenBAmount,
nativeTokenAmount,
);
});
});
109 changes: 109 additions & 0 deletions src/dex/alpaca/alpaca-events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { AlpacaConfig } from './config';
/* eslint-disable no-console */
import dotenv from 'dotenv';
dotenv.config();

import { AlpacaEventPool } from './alpaca-pool';
import { Network } from '../../constants';
import { Address } from '../../types';
import { DummyDexHelper } from '../../dex-helper/index';
import { testEventSubscriber } from '../../../tests/utils-events';
import { PoolState } from './types';

/*
README
======

This test script adds unit tests for Alpaca event based
system. This is done by fetching the state on-chain before the
event block, manually pushing the block logs to the event-subscriber,
comparing the local state with on-chain state.

Most of the logic for testing is abstracted by `testEventSubscriber`.
You need to do two things to make the tests work:

1. Fetch the block numbers where certain events were released. You
can modify the `./scripts/fetch-event-blocknumber.ts` to get the
block numbers for different events. Make sure to get sufficient
number of blockNumbers to cover all possible cases for the event
mutations.

2. Complete the implementation for fetchPoolState function. The
function should fetch the on-chain state of the event subscriber
using just the blocknumber.

The template tests only include the test for a single event
subscriber. There can be cases where multiple event subscribers
exist for a single DEX. In such cases additional tests should be
added.

You can run this individual test script by running:
`npx jest src/dex/<dex-name>/<dex-name>-events.test.ts`

(This comment should be removed from the final implementation)
*/

jest.setTimeout(50 * 1000);

async function fetchPoolState(
alpacaPools: AlpacaEventPool,
blockNumber: number,
poolAddress: string,
): Promise<PoolState> {
return alpacaPools.generateState(blockNumber) as Promise<PoolState>;
}

// eventName -> blockNumbers
type EventMappings = Record<string, number[]>;

describe('Alpaca EventPool BSC', function () {
const dexKey = 'Alpaca';
const network = Network.BSC;
const dexHelper = new DummyDexHelper(network);
const logger = dexHelper.getLogger(dexKey);
let alpacaPool: AlpacaEventPool;

// poolAddress -> EventMappings
const eventsToTest: Record<Address, EventMappings> = {
[AlpacaConfig[dexKey][network].poolDiamond]: {
SWAP_NATIVE: [28695095, 29007167],
SWAP: [28654939, 29008736],
},
};

beforeEach(async () => {
alpacaPool = new AlpacaEventPool(
dexKey,
network,
dexHelper,
logger,
/* TODO: Put here additional constructor arguments if needed */
);
});

Object.entries(eventsToTest).forEach(
([poolAddress, events]: [string, EventMappings]) => {
describe(`Events for ${poolAddress}`, () => {
Object.entries(events).forEach(
([eventName, blockNumbers]: [string, number[]]) => {
describe(`${eventName}`, () => {
blockNumbers.forEach((blockNumber: number) => {
it(`State after ${blockNumber}`, async function () {
await testEventSubscriber(
alpacaPool,
alpacaPool.addressesSubscribed,
(_blockNumber: number) =>
fetchPoolState(alpacaPool, _blockNumber, poolAddress),
blockNumber,
`${dexKey}_${poolAddress}`,
dexHelper.provider,
);
});
});
});
},
);
});
},
);
});
Loading
Loading