-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add script to validate spot prices * Validate asset units in pool * Add script to find bump in on-chain token balance
- Loading branch information
1 parent
cacb02e
commit 8cf7c02
Showing
3 changed files
with
301 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* Script to find change in on-chain token balance of an account between two block numbers | ||
* Run using `ts-node test/findChangeInTokenBalance.ts` | ||
*/ | ||
import SDK, { util } from '@zeitgeistpm/sdk'; | ||
import { Tools } from '../src/mappings/util'; | ||
|
||
// Modify values as per requirement | ||
const WS_NODE_URL = `wss://bsr.zeitgeist.pm`; | ||
const ACCOUNT_ID = `dE1VdxVn8xy7HFNWfF1a8utYcbVN7BHNvTzRndwpRiNfEk9Co`; | ||
const FROM_BLOCK_NUM = 1388585; | ||
const TO_BLOCK_NUM = 1402375; | ||
const MARKET_ID = 44; | ||
const ASSET_INDEX = 0; | ||
|
||
const findChangeInTokenBalance = async () => { | ||
const sdk = await Tools.getSDK(WS_NODE_URL); | ||
let fromBlockNum = FROM_BLOCK_NUM; | ||
let toBlockNum = TO_BLOCK_NUM + 1; // Includes `TO_BLOCK_NUM` for querying | ||
let fromBalance = await getBalanceAt(sdk, fromBlockNum); | ||
const startBalance = BigInt(fromBalance); | ||
|
||
// Inspired by binary search algorithm | ||
while (fromBlockNum <= toBlockNum) { | ||
let midBlockNum = Math.floor((fromBlockNum + toBlockNum) / 2); | ||
const midBalance = await getBalanceAt(sdk, midBlockNum); | ||
|
||
if (fromBalance.toString() !== midBalance.toString()) { | ||
toBlockNum = midBlockNum; | ||
} else { | ||
fromBlockNum = midBlockNum; | ||
fromBalance = midBalance; | ||
} | ||
|
||
// When all block numbers are covered | ||
if (toBlockNum - fromBlockNum == 1) { | ||
const endBalance = BigInt(midBalance); | ||
if (endBalance - startBalance !== BigInt(0)) { | ||
console.log(`\nAddition of ${endBalance - startBalance} units | ||
detected on-chain at #${toBlockNum} for ${ACCOUNT_ID}`); | ||
} else { | ||
console.log(`\nNo change detected in on-chain balance | ||
between #${FROM_BLOCK_NUM} and #${TO_BLOCK_NUM} for ${ACCOUNT_ID}`); | ||
} | ||
sdk.api.disconnect(); | ||
process.exit(1); | ||
} | ||
} | ||
}; | ||
|
||
// To query chain for account balance as on block number | ||
const getBalanceAt = async (sdk: SDK, blockNumber: number) => { | ||
const blockHash = await sdk.api.rpc.chain.getBlockHash(blockNumber); | ||
const data = (await sdk.api.query.tokens.accounts.at( | ||
blockHash, | ||
ACCOUNT_ID, | ||
util.AssetIdFromString(`[${MARKET_ID},${ASSET_INDEX}]`) | ||
)) as any; | ||
console.log(`Balance fetched from #${blockNumber}`); | ||
return data.free.toString(); | ||
}; | ||
|
||
findChangeInTokenBalance(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/** | ||
* Script to validate units of an asset in pool against on-chain data | ||
* Run using `ts-node test/validateHistoricalAssets.ts` | ||
*/ | ||
import { util } from '@zeitgeistpm/sdk'; | ||
import https from 'https'; | ||
import { Tools } from '../src/mappings/util'; | ||
|
||
// Modify values as per requirement | ||
const NODE_URL = `wss://bsr.zeitgeist.pm`; | ||
const QUERY_NODE_HOSTNAME = `processor.bsr.zeitgeist.pm`; | ||
const MARKET_ID = 44; | ||
const ASSET_INDEX = 0; | ||
const POOL_ID = 30; | ||
|
||
// GraphQL query for retrieving balance history of an asset in pool | ||
const query = JSON.stringify({ | ||
query: `{ | ||
historicalAssets(where: {assetId_contains: "[${MARKET_ID},${ASSET_INDEX}]"}, orderBy: id_DESC) { | ||
newAmountInPool | ||
blockNumber | ||
} | ||
accounts(where: {poolId_eq: ${POOL_ID}}) { | ||
accountId | ||
} | ||
}`, | ||
}); | ||
|
||
const options = { | ||
hostname: QUERY_NODE_HOSTNAME, | ||
path: '/graphql', | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'Content-Length': query.length, | ||
'User-Agent': 'Node', | ||
}, | ||
}; | ||
|
||
const req = https.request(options, (res) => { | ||
let data = ''; | ||
res.on('data', (d) => { | ||
data += d; | ||
}); | ||
res.on('end', async () => { | ||
if (res.statusCode == 200) { | ||
console.log(`Validating response received from ${options.hostname}`); | ||
} else { | ||
console.log(JSON.parse(data).errors[0].message); | ||
return; | ||
} | ||
let balanceDiff = BigInt(0), | ||
diffs = ``, | ||
falseBlockNums = ``, | ||
trueBlockNums = ``; | ||
const assetHistory = JSON.parse(data).data.historicalAssets; | ||
const accountId = JSON.parse(data).data.accounts[0].accountId; | ||
console.log( | ||
`Number of records found in balance history of [${MARKET_ID},${ASSET_INDEX}] : ${assetHistory.length}` | ||
); | ||
const sdk = await Tools.getSDK(NODE_URL); | ||
|
||
for (let i = 0; i < assetHistory.length; i++) { | ||
const blockHash = await sdk.api.rpc.chain.getBlockHash( | ||
assetHistory[i].blockNumber | ||
); | ||
const balance = (await sdk.api.query.tokens.accounts.at( | ||
blockHash, | ||
accountId, | ||
util.AssetIdFromString(`[${MARKET_ID},${ASSET_INDEX}]`) | ||
)) as any; | ||
|
||
if (!trueBlockNums.includes(assetHistory[i].blockNumber)) { | ||
if ( | ||
balance.free.toString() !== assetHistory[i].newAmountInPool.toString() | ||
) { | ||
console.log( | ||
`\n${ | ||
assetHistory.length - i | ||
}. Balances don't match at ${blockHash} [#${ | ||
assetHistory[i].blockNumber | ||
}]` | ||
); | ||
console.log(`On Chain: ` + balance.free.toBigInt()); | ||
console.log(`On Subsquid: ` + assetHistory[i].newAmountInPool); | ||
balanceDiff = | ||
balance.free.toBigInt() - BigInt(assetHistory[i].newAmountInPool); | ||
diffs += balanceDiff + `,`; | ||
falseBlockNums += assetHistory[i].blockNumber + `,`; | ||
} else { | ||
console.log( | ||
`${assetHistory.length - i}. Balances match at ${blockHash} [#${ | ||
assetHistory[i].blockNumber | ||
}]` | ||
); | ||
trueBlockNums += assetHistory[i].blockNumber + `,`; | ||
} | ||
} | ||
} | ||
sdk.api.disconnect(); | ||
|
||
if (balanceDiff == BigInt(0)) { | ||
console.log( | ||
`\nAsset balance history on ${accountId} is in alliance with on-chain data` | ||
); | ||
} else { | ||
console.log( | ||
`\nAsset balance history on ${accountId} is not in alliance with on-chain data` | ||
); | ||
const diffsList = diffs.split(','); | ||
const blockNumsList = falseBlockNums.split(','); | ||
console.log(`The differences found are:`); | ||
for (let i = diffsList.length; i > 1; i--) { | ||
console.log(`${diffsList[i - 2]} units at #${blockNumsList[i - 2]}`); | ||
} | ||
} | ||
process.exit(1); | ||
}); | ||
}); | ||
|
||
req.on('error', (error) => { | ||
console.error(error); | ||
}); | ||
|
||
req.write(query); | ||
req.end(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/** | ||
* Script to validate spot price of an asset against on-chain price | ||
* Run using `ts-node test/validateSpotPrices.ts` | ||
*/ | ||
import https from 'https'; | ||
import { Tools } from '../src/mappings/util'; | ||
|
||
// Modify values as per requirement | ||
const NODE_URL = `wss://bsr.zeitgeist.pm`; | ||
const QUERY_NODE_HOSTNAME = `processor.bsr.zeitgeist.pm`; | ||
const ASSETS_LIMIT = 100; // Number of assets that need to be validated | ||
|
||
// GraphQL query for retrieving price of assets | ||
const query = JSON.stringify({ | ||
query: `{ | ||
assets(limit: ${ASSETS_LIMIT}, orderBy: id_DESC) { | ||
assetId | ||
price | ||
poolId | ||
} | ||
squidStatus { | ||
height | ||
} | ||
}`, | ||
}); | ||
|
||
const options = { | ||
hostname: QUERY_NODE_HOSTNAME, | ||
path: '/graphql', | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'Content-Length': query.length, | ||
'User-Agent': 'Node', | ||
}, | ||
}; | ||
|
||
const req = https.request(options, (res) => { | ||
let data = ''; | ||
res.on('data', (d) => { | ||
data += d; | ||
}); | ||
res.on('end', async () => { | ||
if (res.statusCode == 200) { | ||
console.log(`Validating response received from ${options.hostname}`); | ||
} else { | ||
console.log(JSON.parse(data).errors[0].message); | ||
return; | ||
} | ||
let falseCounter = 0, | ||
trueCounter = 0, | ||
falseAssets = ``; | ||
const assets = JSON.parse(data).data.assets; | ||
const sdk = await Tools.getSDK(NODE_URL); | ||
|
||
const blockHash = await sdk.api.rpc.chain.getBlockHash( | ||
JSON.parse(data).data.squidStatus.height | ||
); | ||
console.log(); | ||
|
||
for (let i = 0; i < assets.length; i++) { | ||
//Remove exceptions | ||
if (assets[i].assetId.includes('scalar')) continue; | ||
if (assets[i].price == 0 || assets[i].price == 1) continue; | ||
|
||
const pool = await sdk.models.fetchPoolData(Number(assets[i].poolId)); | ||
//@ts-ignore | ||
let price = await pool.getSpotPrice({ ztg: null }, assets[i].assetId, blockHash); | ||
price = Number(price) / Math.pow(10, 10); | ||
|
||
const chainPrice = Math.round(price * 10); //Round to one decimal place | ||
const squidPrice = Math.round(assets[i].price * 10) ?? 0; | ||
if (chainPrice !== squidPrice) { | ||
falseCounter++; | ||
falseAssets += | ||
`${assets[i].assetId} - pool id ${assets[i].poolId}` + `|`; | ||
console.log( | ||
`\n${trueCounter + falseCounter}. Prices don't match for ${ | ||
assets[i].assetId | ||
} of pool id ${assets[i].poolId}` | ||
); | ||
console.log(`On Chain: ` + price); | ||
console.log(`On Subsquid: ` + assets[i].price); | ||
console.log(); | ||
} else { | ||
trueCounter++; | ||
console.log( | ||
`${trueCounter + falseCounter}. Prices match for ` + assets[i].assetId | ||
); | ||
} | ||
} | ||
sdk.api.disconnect(); | ||
|
||
console.log(`\nTotal assets checked: ${trueCounter + falseCounter}`); | ||
console.log(`Prices match for ${trueCounter} assets`); | ||
if (falseCounter > 0) { | ||
const falseAssetsList = falseAssets.split('|'); | ||
console.log(`Prices don't match for the below ${falseCounter} asset(s):`); | ||
for (let a in falseAssetsList) { | ||
console.log(falseAssetsList[a]); | ||
} | ||
} | ||
process.exit(1); | ||
}); | ||
}); | ||
|
||
req.on('error', (error) => { | ||
console.error(error); | ||
}); | ||
|
||
req.write(query); | ||
req.end(); |