Skip to content

Commit

Permalink
Merge pull request #194 from Synthetixio/fee-records
Browse files Browse the repository at this point in the history
minor updates for subgraph recording of fees
  • Loading branch information
dbeal-eth authored Jun 23, 2022
2 parents 0fd0712 + 786357d commit 352f1a4
Show file tree
Hide file tree
Showing 11 changed files with 3,943 additions and 4,239 deletions.
7,956 changes: 3,757 additions & 4,199 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"commander": "8.2.0",
"eslint-config-prettier": "^8.3.0",
"mustache": "4.2.0",
"synthetix": "^2.71.0"
"synthetix": "^2.73.1"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "4.32.0",
Expand Down
23 changes: 8 additions & 15 deletions src/exchanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
strToBytes,
ZERO,
YEAR_SECONDS,
getExchangeFee,
} from './lib/helpers';
import { toDecimal, ZERO_ADDRESS } from './lib/helpers';
import { addDollar, addProxyAggregator } from './fragments/latest-rates';
Expand Down Expand Up @@ -184,13 +185,9 @@ export function handleSynthExchange(event: SynthExchangeEvent): void {
let fromAmountInUSD = getUSDAmountFromAssetAmount(event.params.fromAmount, latestFromRate);
let toAmountInUSD = getUSDAmountFromAssetAmount(event.params.toAmount, latestToRate);

let feesInUSD = fromAmountInUSD.minus(toAmountInUSD);

if (feesInUSD.lt(toDecimal(ZERO))) {
let DEFAULT_FEE = toDecimal(BigInt.fromI32(3), 3);
// this is an edge case. we can get pretty close to accurate by use of best guess of 30 bp
feesInUSD = fromAmountInUSD.times(DEFAULT_FEE);
}
let feesInUSD = fromAmountInUSD.times(
getExchangeFee('exchangeFeeRate', fromCurrencyKey == 'sUSD' ? toCurrencyKey : fromCurrencyKey),
);

let fromSynth = SynthByCurrencyKey.load(fromCurrencyKey);
let toSynth = SynthByCurrencyKey.load(toCurrencyKey);
Expand Down Expand Up @@ -269,17 +266,13 @@ export function handleAtomicSynthExchange(event: AtomicSynthExchangeEvent): void
let fromAmountInUSD = getUSDAmountFromAssetAmount(event.params.fromAmount, latestFromRate);
let toAmountInUSD = getUSDAmountFromAssetAmount(event.params.toAmount, latestToRate);

let feesInUSD = fromAmountInUSD.minus(toAmountInUSD);

if (feesInUSD.lt(toDecimal(ZERO))) {
let DEFAULT_FEE = toDecimal(BigInt.fromI32(3), 3);
// this is an edge case. we can get pretty close to accurate by use of best guess of 30 bp
feesInUSD = fromAmountInUSD.times(DEFAULT_FEE);
}

let fromSynth = SynthByCurrencyKey.load(fromCurrencyKey);
let toSynth = SynthByCurrencyKey.load(toCurrencyKey);

let feesInUSD = fromAmountInUSD.times(
getExchangeFee('atomicExchangeFeeRate', fromCurrencyKey == 'sUSD' ? toCurrencyKey : fromCurrencyKey),
);

let fromSynthAddress = fromSynth != null ? fromSynth.proxyAddress : ZERO_ADDRESS;
let toSynthAddress = toSynth != null ? toSynth.proxyAddress : ZERO_ADDRESS;

Expand Down
62 changes: 62 additions & 0 deletions src/fragments/latest-rates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import {
AggregatorConfirmed as AggregatorConfirmedEvent,
} from '../../generated/subgraphs/latest-rates/ExchangeRates_13/AggregatorProxy';

import {
ExchangeFeeUpdated,
AtomicExchangeFeeUpdated,
SystemSettings,
} from '../../generated/subgraphs/latest-rates/latestRates-SystemSettings_0/SystemSettings';

import { AnswerUpdated as AnswerUpdatedEvent } from '../../generated/subgraphs/latest-rates/templates/Aggregator/Aggregator';

import {
Expand All @@ -25,6 +31,7 @@ import {
LatestRate,
InversePricingInfo,
RateUpdate,
FeeRate,
DailyCandle,
Candle,
} from '../../generated/subgraphs/latest-rates/schema';
Expand Down Expand Up @@ -232,6 +239,43 @@ export function initFeed(currencyKey: string): BigDecimal | null {
return null;
}

export function initFeeRate(type: string, currencyKey: string): BigDecimal {
let addressResolverAddress = getContractDeployment(
'AddressResolver',
dataSource.network(),
BigInt.fromI32(1000000000),
)!;

let resolver = AddressResolver.bind(addressResolverAddress);
let systemSettingsAddressTry = resolver.try_getAddress(strToBytes('SystemSettings', 32));

if (!systemSettingsAddressTry.reverted) {
let ss = SystemSettings.bind(systemSettingsAddressTry.value);

let result = ss.try_atomicExchangeFeeRate(strToBytes(currencyKey, 32));
if (type === 'exchangeFeeRate') {
result = ss.try_exchangeFeeRate(strToBytes(currencyKey, 32));
// eslint-disable-next-line no-empty
} else if (type === 'atomicExchangeFeeRate') {
} else {
log.warning('unknown fee type {}', [type]);
return toDecimal(BigInt.fromI32(0));
}

if (!result.reverted) {
let entity = new FeeRate(type + '-' + currencyKey);
entity.setting = type;
entity.synth = currencyKey;
entity.rate = toDecimal(result.value);
entity.save();

return toDecimal(result.value);
}
}

return toDecimal(BigInt.fromI32(0));
}

export function handleAggregatorAdded(event: AggregatorAddedEvent): void {
addProxyAggregator(event.params.currencyKey.toString(), event.params.aggregator);
}
Expand Down Expand Up @@ -355,6 +399,24 @@ export function handleChainlinkUpdate(event: ExecutionSuccess): void {
}
}

export function handleExchangeFeeUpdated(event: ExchangeFeeUpdated): void {
let entity = new FeeRate('exchangeFeeRate-' + event.params.synthKey.toString());
entity.setting = 'exchangeFee';
entity.synth = event.params.synthKey.toString();
entity.rate = toDecimal(event.params.newExchangeFeeRate);
entity.save();
return;
}

export function handleAtomicExchangeFeeUpdated(event: AtomicExchangeFeeUpdated): void {
let entity = new FeeRate('atomicExchangeFeeRate-' + event.params.synthKey.toString());
entity.setting = 'atomicExchangeFeeRate';
entity.synth = event.params.synthKey.toString();
entity.rate = toDecimal(event.params.newExchangeFeeRate);
entity.save();
return;
}

// DEPRECATED: See updateCandle
function updateDailyCandle(timestamp: BigInt, synth: string, rate: BigDecimal): void {
let dayID = timestamp.toI32() / 86400;
Expand Down
15 changes: 13 additions & 2 deletions src/lib/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BigDecimal, BigInt, Bytes, ByteArray, log, Address, dataSource } from '@graphprotocol/graph-ts';

import { LatestRate } from '../../generated/subgraphs/latest-rates/schema';
import { initFeed } from '../fragments/latest-rates';
import { LatestRate, FeeRate } from '../../generated/subgraphs/latest-rates/schema';
import { initFeed, initFeeRate } from '../fragments/latest-rates';
import { getContractDeployment } from '../../generated/addresses';

export let ZERO = BigInt.fromI32(0);
Expand Down Expand Up @@ -60,6 +60,17 @@ export function getLatestRate(synth: string, txHash: string): BigDecimal | null
return latestRate.rate;
}

export function getExchangeFee(type: string, synth: string): BigDecimal {
let rate = FeeRate.load(type + '-' + synth);
if (rate == null) {
log.warning('atomic exchange rate missing for synth: {}', [synth]);

// load feed for the first time, and use contract call to get rate
return initFeeRate(type, synth);
}
return rate.rate;
}

export function isEscrow(holder: string, network: string): boolean {
return (
getContractDeployment('SynthetixEscrow', dataSource.network(), BigInt.fromI32(1000000000))!.toHexString() ==
Expand Down
5 changes: 4 additions & 1 deletion subgraphs/exchanger.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ getContractDeployments('ProxyERC20').forEach((a, i) => {
network: getCurrentNetwork(),
source: {
address: a.address,
startBlock: i === 0 && getCurrentNetwork() === 'mainnet' ? 12733161 : a.startBlock,
startBlock:
i === 0 && getCurrentNetwork() === 'mainnet'
? Math.max(parseInt(process.env.SNX_START_BLOCK || '0'), 12733161)
: a.startBlock,
abi: 'Synthetix',
},
mapping: {
Expand Down
39 changes: 21 additions & 18 deletions subgraphs/exchanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ const { getContractDeployments, getCurrentNetwork, createSubgraphManifest } = re
const latestRates = require('./fragments/latest-rates');
const balances = require('./fragments/balances');

const manifest = clone(latestRates.dataSources);
manifest.push(...balances.dataSources);
const manifest = [];

if (getCurrentNetwork() == 'mainnet') {
manifest.push(
Expand All @@ -17,14 +16,14 @@ if (getCurrentNetwork() == 'mainnet') {
source: {
address: '0xc011a72400e58ecd99ee497cf89e3775d4bd732f',
abi: 'Synthetix4',
startBlock: 6841188,
startBlock: Math.max(parseInt(process.env.SNX_START_BLOCK || '0'), 6841188),
},
mapping: {
kind: 'ethereum/events',
apiVersion: '0.0.5',
language: 'wasm/assemblyscript',
file: '../src/exchanges.ts',
entities: ['SynthExchange'],
entities: ['SynthExchange', 'FeeRate'],
abis: [
{
name: 'Synthetix4',
Expand All @@ -50,6 +49,10 @@ if (getCurrentNetwork() == 'mainnet') {
name: 'AggregatorProxy',
file: '../abis/AggregatorProxy.json',
},
{
name: 'SystemSettings',
file: '../abis/SystemSettings.json',
},
],
eventHandlers: [
{
Expand All @@ -66,14 +69,14 @@ if (getCurrentNetwork() == 'mainnet') {
source: {
address: '0xc011a72400e58ecd99ee497cf89e3775d4bd732f',
abi: 'Synthetix',
startBlock: 8622911,
startBlock: Math.max(parseInt(process.env.SNX_START_BLOCK || '0'), 8622911),
},
mapping: {
kind: 'ethereum/events',
apiVersion: '0.0.5',
language: 'wasm/assemblyscript',
file: '../src/exchanges.ts',
entities: ['SynthExchange', 'ExchangeReclaim', 'ExchangeRebate'],
entities: ['SynthExchange', 'ExchangeReclaim', 'ExchangeRebate', 'FeeRate'],
abis: [
{
name: 'Synthetix4',
Expand All @@ -95,6 +98,10 @@ if (getCurrentNetwork() == 'mainnet') {
name: 'ExchangeRates',
file: '../abis/ExchangeRates.json',
},
{
name: 'SystemSettings',
file: '../abis/SystemSettings.json',
},
],
eventHandlers: [
{
Expand Down Expand Up @@ -130,7 +137,7 @@ getContractDeployments('ProxyERC20').forEach((a, i) => {
apiVersion: '0.0.5',
language: 'wasm/assemblyscript',
file: '../src/exchanges.ts',
entities: ['SynthExchange', 'ExchangeReclaim', 'ExchangeRebate'],
entities: ['SynthExchange', 'ExchangeReclaim', 'ExchangeRebate', 'FeeRate'],
abis: [
{
name: 'Synthetix4',
Expand All @@ -156,6 +163,10 @@ getContractDeployments('ProxyERC20').forEach((a, i) => {
name: 'AggregatorProxy',
file: '../abis/AggregatorProxy.json',
},
{
name: 'SystemSettings',
file: '../abis/SystemSettings.json',
},
],
eventHandlers: [
{
Expand Down Expand Up @@ -275,15 +286,7 @@ let futuresMarketTemplate = {
},
};

module.exports = createSubgraphManifest('exchanges', manifest, latestRates.templates.concat([futuresMarketTemplate]));
manifest.push(...balances.dataSources);
manifest.push(...latestRates.dataSources);

module.exports = {
specVersion: '0.0.2',
description: 'Synthetix Exchanges API',
repository: 'https://github.com/Synthetixio/synthetix-subgraph',
schema: {
file: './exchanges.graphql',
},
dataSources: manifest,
templates: latestRates.templates.concat([futuresMarketTemplate]),
};
module.exports = createSubgraphManifest('exchanges', manifest, [...latestRates.templates, futuresMarketTemplate]);
47 changes: 46 additions & 1 deletion subgraphs/fragments/latest-rates.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const { getContractDeployments, versions, getCurrentNetwork, getCurrentSubgraph } = require('../utils/network');

const exchangeRatesContractAddresses = getContractDeployments('ExchangeRates');
const systemSettingsAddresses = getContractDeployments('SystemSettings');
console.log('systemsettings', systemSettingsAddresses.length);

const systemSettingsManifests = [];
const exchangeRatesManifests = [];

// the rates updated event changed from bytes4 to bytes32 in the sirius release
Expand All @@ -14,6 +17,48 @@ const EXCHANGES_START_BLOCK = 6841188;
// the earliest start block to track shorts subgraph rates
const SHORTS_START_BLOCK = 11513382;

systemSettingsAddresses.forEach((a, i) => {
console.log('adding a system settings', a);
systemSettingsManifests.push({
kind: 'ethereum/contract',
// for some reason sUSD has different contract name
name: `latestRates-SystemSettings_${i}`,
network: getCurrentNetwork(),
source: {
address: a.address,
startBlock: a.startBlock,
abi: 'SystemSettings',
},
mapping: {
kind: 'ethereum/events',
apiVersion: '0.0.5',
language: 'wasm/assemblyscript',
file: '../src/fragments/latest-rates.ts',
entities: ['FeeRate'],
abis: [
{
name: 'Synth',
file: '../abis/Synth.json',
},
{
name: 'SystemSettings',
file: '../abis/SystemSettings.json',
},
],
eventHandlers: [
{
event: 'ExchangeFeeUpdated(bytes32,uint256)',
handler: 'handleExchangeFeeUpdated',
},
{
event: 'AtomicExchangeFeeUpdated(bytes32,uint256)',
handler: 'handleAtomicExchangeFeeUpdated',
},
],
},
});
});

exchangeRatesContractAddresses.forEach((ca, i) => {
let startBlock = ca.startBlock;
if (getCurrentSubgraph() === 'exchanger' && startBlock < EXCHANGER_START_BLOCK) {
Expand Down Expand Up @@ -278,6 +323,6 @@ const inverseAggregatorTemplate = {
};

module.exports = {
dataSources: exchangeRatesManifests,
dataSources: [...exchangeRatesManifests, ...systemSettingsManifests],
templates: [...proxyTemplates, aggregatorTemplate, synthAggregatorTemplate, inverseAggregatorTemplate],
};
13 changes: 13 additions & 0 deletions subgraphs/latest-rates.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ type RateUpdate @entity {
timestamp: BigInt!
}

type FeeRate @entity {
" string representing the setting name "
id: ID!

setting: String!

" name of the synth this record applies to, if any "
synth: String

" value of the setting "
rate: BigDecimal!
}

" DEPRECATED: See the Candles entity"
type DailyCandle @entity {
" DEPRECATED: See the Candles entity "
Expand Down
10 changes: 10 additions & 0 deletions subgraphs/main.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,16 @@ type ActiveStaker @entity {
id: ID!
}

type FeeRate @entity {
" string representing the setting name "
id: ID!
setting: String!
" name of the synth this record applies to, if any "
synth: String
" value of the setting "
rate: BigDecimal!
}

type AccountFlaggedForLiquidation @entity {
" the deadline plus the staker address "
id: ID!
Expand Down
Loading

0 comments on commit 352f1a4

Please sign in to comment.