[Issue] Multiple anchor liquidation message in single transaciton.
Closed this issue · 2 comments
Why?
I am trying to build stg table for anchor liquidation, and I find the event_attributes
is very complicated and multiple liquidation is usually involved. e.g. https://terrasco.pe/mainnet/tx/14B04061E46C4AE922CBE25A00AED77415E65F0C346C215097D57FE84AFC9303
What?
I've seen int_anchor_liquidations
trying to select the first liquidation message from each tx. I have been thinking if any better way to select all pair of liquidations?
How?
One possible solution is UDF, which may be not efficient enough but more handy.
const parseAnchorLiquidate = (attrs) => {
// Prepare map of attributes for all existing type
var cache = {
action: [],
amount: [],
borrower: [],
liquidator: [],
from: [],
to: [],
holder_address: [],
stable_denom: [],
repay_amount: [],
bid_fee: [],
liquidator_fee: [],
collateral_token: [],
collateral_amount: [],
contract_address: [],
provided_liquidity: [],
addr_count: [],
};
// Classify all attributes by postfix, with single item type handled
for (const [key, value] of Object.entries(attrs)) {
// Pre-defined value for single item without {\d+_} prefix
let keyIndex = 0,
keyPostfix = key;
if (/^\d/.test(key)) {
let splitted = key.match(/^(\d+)_(.+)$/);
keyIndex = parseInt(splitted[1]);
keyPostfix = splitted[2];
}
cache[keyPostfix].push({ index: keyIndex, value: value });
}
// Each attributes are re-ordered by the integer prefix,
// but not string comparison.
for (const key of Object.keys(cache)) {
cache[key] = cache[key]
.sort((a, b) => a.index - b.index)
.map((item) => item.value);
}
var result = [];
// Based on the above map, we re-group all the attributes by action
// assuming that all action's optional field exists.
// Otherwise it will be so difficult to parse the data.
for (const action of cache.action) {
let amount,
borrower,
liquidator,
from,
to,
holder_address,
stable_denom,
repay_amount,
bid_fee,
liquidator_fee,
collateral_token,
collateral_amount,
contract_address;
switch (action) {
case "liquidate_collateral":
liquidator = cache.liquidator.shift();
amount = cache.amount.shift();
borrower = cache.borrower.shift();
contract_address = cache.contract_address.shift();
result.push({
action,
liquidator,
borrower,
amount,
contract_address,
});
break;
case "execute_bid":
stable_denom = cache.stable_denom.shift();
repay_amount = cache.repay_amount.shift();
bid_fee = cache.bid_fee.shift();
liquidator_fee = cache.liquidator_fee.shift();
collateral_token = cache.collateral_token.shift();
collateral_amount = cache.collateral_amount.shift();
contract_address = cache.contract_address.shift();
result.push({
action,
stable_denom,
repay_amount,
bid_fee,
liquidator_fee,
collateral_token,
collateral_amount,
contract_address,
});
break;
case "repay_stable":
borrower = cache.borrower.shift();
repay_amount = cache.repay_amount.shift();
contract_address = cache.contract_address.shift();
result.push({
action,
borrower,
repay_amount,
contract_address,
});
break;
// we can even ignore all the result here, updating the array's index
// is sufficient for the algo.
case "send":
to = cache.to.shift();
from = cache.from.shift();
amount = cache.amount.shift();
contract_address = cache.contract_address.shift();
result.push({ action, to, from, amount, contract_address });
break;
case "decrease_balance":
case "increase_balance":
holder_address = cache.holder_address.shift();
amount = cache.amount.shift();
contract_address = cache.contract_address.shift();
result.push({ action, holder_address, amount, contract_address });
break;
}
}
// I am only interested in execute_bid and liquidate_collateral,
// while repay_stable case should be also useful.
cache = result.filter(
(item) =>
item.action === "execute_bid" || item.action === "liquidate_collateral"
);
result = [];
// Again, wild assumption here that execute_bid and liquidate_collateral
// actions are always in pairs.
for (let i = 0; i < cache.length; i += 2) {
chunk = cache.slice(i, i + 2);
result.push({
liquidator: chunk[0].liquidator,
borrower: chunk[0].borrower,
repay_amount: chunk[1].repay_amount,
bid_fee: chunk[1].bid_fee,
liquidator_fee: chunk[1].liquidator_fee,
collateral_token: chunk[1].collateral_token,
collateral_amount: chunk[1].collateral_amount,
});
}
return result;
};
I updated the JS function above as tested to be working quite well. Still doing some testing / confirmation work but you can see if how the idea goes.
@kavimaluskam rip
if you are still interested in dbt and data curation, we are starting terra 2 models soon at MetricsDAO