Skip to content
Draft
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 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ web_modules/
.env.test.local
.env.production.local
.env.local
.env.tenderly

# parcel-bundler cache (https://parceljs.org/)
.cache
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@
"generate-merkl-csv": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/generate-csv.ts",
"compare-csv": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/compare-csv-files.ts",
"analyze-csv-differences": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/analyze-differences.ts",
"calculate-csv-totals": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/calculate-totals.ts"
"calculate-csv-totals": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/calculate-totals.ts",
"tenderly:testnet": "bash src/scripts/tenderly-testnet.sh",
"tenderly:testnet:delete": "bash src/scripts/tenderly-testnet-delete.sh",
"tenderly:testnet:test": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/tenderly-testnet-test.ts",
"tenderly:testnet:generate": "TZ=UTC ts-node -r tsconfig-paths/register src/scripts/tenderly-generate-data.ts"
},
"dependencies": {
"@codex-data/sdk": "^0.6.2",
Expand Down
247 changes: 247 additions & 0 deletions src/abis/GradientController.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/**
* Minimal ABI for GradientController contract.
* The GradientController shares the same pairs()/strategiesByPair()/strategiesByPairCount() interface
* as CarbonController, but with gradient-specific order tuples.
*
* Order tuple: (uint128 liquidity, uint64 initialPrice, uint32 tradingStartTime, uint32 expiry, uint32 multiFactor, uint8 gradientType)
*/
export const GradientController: any[] = [
{
inputs: [
{ internalType: 'uint128', name: 'startIndex', type: 'uint128' },
{ internalType: 'uint128', name: 'endIndex', type: 'uint128' },
],
name: 'pairs',
outputs: [
{
components: [
{ internalType: 'address', name: 'token0', type: 'address' },
{ internalType: 'address', name: 'token1', type: 'address' },
],
internalType: 'struct Token[2][]',
name: '',
type: 'tuple[]',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ internalType: 'address', name: 'token0', type: 'address' },
{ internalType: 'address', name: 'token1', type: 'address' },
],
name: 'strategiesByPairCount',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ internalType: 'address', name: 'token0', type: 'address' },
{ internalType: 'address', name: 'token1', type: 'address' },
{ internalType: 'uint256', name: 'startIndex', type: 'uint256' },
{ internalType: 'uint256', name: 'endIndex', type: 'uint256' },
],
name: 'strategiesByPair',
outputs: [
{
components: [
{ internalType: 'uint256', name: 'id', type: 'uint256' },
{ internalType: 'address', name: 'owner', type: 'address' },
{ internalType: 'address[2]', name: 'tokens', type: 'address[2]' },
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
internalType: 'struct Order[2]',
name: 'orders',
type: 'tuple[2]',
},
],
internalType: 'struct Strategy[]',
name: '',
type: 'tuple[]',
},
],
stateMutability: 'view',
type: 'function',
},
{
anonymous: false,
inputs: [
{ indexed: false, internalType: 'uint256', name: 'id', type: 'uint256' },
{ indexed: true, internalType: 'address', name: 'owner', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token0', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token1', type: 'address' },
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
indexed: false,
internalType: 'struct Order',
name: 'order0',
type: 'tuple',
},
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
indexed: false,
internalType: 'struct Order',
name: 'order1',
type: 'tuple',
},
],
name: 'StrategyCreated',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'uint256', name: 'id', type: 'uint256' },
{ indexed: true, internalType: 'address', name: 'token0', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token1', type: 'address' },
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
indexed: false,
internalType: 'struct Order',
name: 'order0',
type: 'tuple',
},
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
indexed: false,
internalType: 'struct Order',
name: 'order1',
type: 'tuple',
},
],
name: 'StrategyUpdated',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: false, internalType: 'uint256', name: 'id', type: 'uint256' },
{ indexed: true, internalType: 'address', name: 'owner', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token0', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token1', type: 'address' },
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
indexed: false,
internalType: 'struct Order',
name: 'order0',
type: 'tuple',
},
{
components: [
{ internalType: 'uint128', name: 'liquidity', type: 'uint128' },
{ internalType: 'uint64', name: 'initialPrice', type: 'uint64' },
{ internalType: 'uint32', name: 'tradingStartTime', type: 'uint32' },
{ internalType: 'uint32', name: 'expiry', type: 'uint32' },
{ internalType: 'uint32', name: 'multiFactor', type: 'uint32' },
{ internalType: 'uint8', name: 'gradientType', type: 'uint8' },
],
indexed: false,
internalType: 'struct Order',
name: 'order1',
type: 'tuple',
},
],
name: 'StrategyDeleted',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'address', name: 'trader', type: 'address' },
{ indexed: true, internalType: 'address', name: 'sourceToken', type: 'address' },
{ indexed: true, internalType: 'address', name: 'targetToken', type: 'address' },
{ indexed: false, internalType: 'uint256', name: 'sourceAmount', type: 'uint256' },
{ indexed: false, internalType: 'uint256', name: 'targetAmount', type: 'uint256' },
{ indexed: false, internalType: 'uint128', name: 'tradingFeeAmount', type: 'uint128' },
{ indexed: false, internalType: 'bool', name: 'byTargetAmount', type: 'bool' },
],
name: 'TokensTraded',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'uint128', name: 'pairId', type: 'uint128' },
{ indexed: true, internalType: 'address', name: 'token0', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token1', type: 'address' },
],
name: 'PairCreated',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'uint256', name: 'id', type: 'uint256' },
{ indexed: true, internalType: 'address', name: 'token0', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token1', type: 'address' },
{ indexed: false, internalType: 'uint128', name: 'liquidity0', type: 'uint128' },
{ indexed: false, internalType: 'uint128', name: 'liquidity1', type: 'uint128' },
],
name: 'StrategyLiquidityUpdated',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: false, internalType: 'uint32', name: 'prevFeePPM', type: 'uint32' },
{ indexed: false, internalType: 'uint32', name: 'newFeePPM', type: 'uint32' },
],
name: 'TradingFeePPMUpdated',
type: 'event',
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'address', name: 'token0', type: 'address' },
{ indexed: true, internalType: 'address', name: 'token1', type: 'address' },
{ indexed: false, internalType: 'uint32', name: 'prevFeePPM', type: 'uint32' },
{ indexed: false, internalType: 'uint32', name: 'newFeePPM', type: 'uint32' },
],
name: 'PairTradingFeePPMUpdated',
type: 'event',
},
];
5 changes: 5 additions & 0 deletions src/activity/activity-v2.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { StrategyCreatedEventService } from '../events/strategy-created-event/st
import { StrategyUpdatedEventService } from '../events/strategy-updated-event/strategy-updated-event.service';
import { StrategyDeletedEventService } from '../events/strategy-deleted-event/strategy-deleted-event.service';
import { VoucherTransferEventService } from '../events/voucher-transfer-event/voucher-transfer-event.service';
import { GradientStrategyCreatedEventService } from '../gradient/events/gradient-strategy-created-event.service';
import { BlockchainType, Deployment, ExchangeId } from '../deployment/deployment.service';
import { TokensByAddress } from '../token/token.service';
import { StrategyCreatedEvent } from '../events/strategy-created-event/strategy-created-event.entity';
Expand Down Expand Up @@ -195,6 +196,10 @@ describe('ActivityV2Service', () => {
provide: VoucherTransferEventService,
useValue: { get: jest.fn() },
},
{
provide: GradientStrategyCreatedEventService,
useValue: { all: jest.fn().mockResolvedValue([]) },
},
],
}).compile();

Expand Down
14 changes: 11 additions & 3 deletions src/activity/activity-v2.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { StrategyCreatedEventService } from '../events/strategy-created-event/st
import { StrategyUpdatedEventService } from '../events/strategy-updated-event/strategy-updated-event.service';
import { StrategyDeletedEventService } from '../events/strategy-deleted-event/strategy-deleted-event.service';
import { VoucherTransferEventService } from '../events/voucher-transfer-event/voucher-transfer-event.service';
import { GradientStrategyCreatedEventService } from '../gradient/events/gradient-strategy-created-event.service';
import { StrategyState, StrategyStatesMap } from './activity.types';
import { createActivityFromEvent, ordersEqual, parseOrder, processOrders } from './activity.utils';
import { TokensByAddress } from '../token/token.service';
Expand All @@ -30,6 +31,7 @@ export class ActivityV2Service {
private strategyUpdatedEventService: StrategyUpdatedEventService,
private strategyDeletedEventService: StrategyDeletedEventService,
private voucherTransferEventService: VoucherTransferEventService,
private gradientStrategyCreatedEventService: GradientStrategyCreatedEventService,
private lastProcessedBlockService: LastProcessedBlockService,
) {}

Expand Down Expand Up @@ -681,9 +683,15 @@ export class ActivityV2Service {
): Promise<void> {
strategyStates.clear();

// Get all creation events using the all() method
const creationEvents = await this.strategyCreatedEventService.all(deployment);
const creationEventsByStrategyId = new Map(creationEvents.map((event) => [event.strategyId, event]));
const creationEventsByStrategyId = new Map<string, { owner: string }>(
creationEvents.map((event) => [event.strategyId, event]),
);

const gradientCreationEvents = await this.gradientStrategyCreatedEventService.all(deployment);
for (const event of gradientCreationEvents) {
creationEventsByStrategyId.set(event.strategyId, event);
}

// Get the last events for each strategy
const lastEvents = await this.activityRepository
Expand All @@ -706,7 +714,7 @@ export class ActivityV2Service {

strategyStates.set(activity.strategyId, {
currentOwner: activity.currentOwner,
creationWallet: creationEvent.owner,
creationWallet: creationEvent ? creationEvent.owner : activity.currentOwner,
order0: activity.order0,
order1: activity.order1,
token0: activity.token0,
Expand Down
2 changes: 2 additions & 0 deletions src/activity/activity.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { StrategyCreatedEventModule } from '../events/strategy-created-event/str
import { StrategyUpdatedEventModule } from '../events/strategy-updated-event/strategy-updated-event.module';
import { StrategyDeletedEventModule } from '../events/strategy-deleted-event/strategy-deleted-event.module';
import { VoucherTransferEventModule } from '../events/voucher-transfer-event/voucher-transfer-event.module';
import { GradientModule } from '../gradient/gradient.module';
@Module({
imports: [
TypeOrmModule.forFeature([ActivityV2]),
Expand All @@ -15,6 +16,7 @@ import { VoucherTransferEventModule } from '../events/voucher-transfer-event/vou
StrategyUpdatedEventModule,
StrategyDeletedEventModule,
VoucherTransferEventModule,
GradientModule,
],
providers: [ActivityV2Service],
exports: [ActivityV2Service],
Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { CarbonPriceModule } from './carbon-price/carbon-price.module';
import { MerklModule } from './merkl/merkl.module';
import { WalletPairBalanceModule } from './wallet-pair-balance/wallet-pair-balance.module';
import { StrategyRealtimeModule } from './strategy-realtime/strategy-realtime.module';
import { GradientModule } from './gradient/gradient.module';

@Module({
imports: [
Expand Down Expand Up @@ -114,6 +115,7 @@ import { StrategyRealtimeModule } from './strategy-realtime/strategy-realtime.mo
MerklModule,
WalletPairBalanceModule,
StrategyRealtimeModule,
GradientModule,
],

providers: [
Expand Down
12 changes: 12 additions & 0 deletions src/deployment/deployment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface Deployment {
ethereumAddress: string;
};
};
gradientTimestampOffset?: number;
contracts: {
[contractName: string]: {
address: string;
Expand Down Expand Up @@ -138,7 +139,14 @@ export class DeploymentService {
LiquidityProtectionStore: {
address: '0xf5FAB5DBD2f3bf675dE4cB76517d4767013cfB55',
},
GradientController: {
address: this.configService.get('ETHEREUM_GRADIENT_CONTROLLER_ADDRESS') || '',
},
GradientVoucher: {
address: this.configService.get('ETHEREUM_GRADIENT_VOUCHER_ADDRESS') || '',
},
},
gradientTimestampOffset: 60,
notifications: {
explorerUrl: this.configService.get('ETHEREUM_EXPLORER_URL'),
carbonWalletUrl: this.configService.get('ETHEREUM_CARBON_WALLET_URL'),
Expand Down Expand Up @@ -798,6 +806,10 @@ export class DeploymentService {
* @param tokenAddress - The token address to check (case-insensitive)
* @returns true if the token should be ignored from pricing
*/
hasGradientSupport(deployment: Deployment): boolean {
return !!(deployment.contracts.GradientController?.address && deployment.gradientTimestampOffset);
}

isTokenIgnoredFromPricing(deployment: Deployment, tokenAddress: string): boolean {
if (!deployment.pricingIgnoreList || deployment.pricingIgnoreList.length === 0) {
return false;
Expand Down
Loading