-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implementation for THALA SUSDE LP tracking
- Loading branch information
1 parent
de65fbf
commit cb10453
Showing
6 changed files
with
252 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
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
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 @@ | ||
SUSDE_LPT_METADATA = "0x99d34f16193e251af236d5a5c3114fa54e22ca512280317eda2f8faf1514c395" # TODO: APT/USDT Address for now |
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
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 @@ | ||
import logging | ||
import subprocess | ||
import json | ||
|
||
from typing import Dict, List | ||
from dotenv import load_dotenv | ||
from constants.summary_columns import SummaryColumn | ||
from constants.example_integrations import ( | ||
THALA_SUSDE_START_BLOCK, | ||
) | ||
from constants.thala import THALASWAP_CONTRACT_ADDRESS, SUSDE_LPT_METADATA, SUSDE_TOKEN_ADDRESS | ||
from constants.chains import Chain | ||
from integrations.integration_ids import IntegrationID as IntID | ||
from integrations.l2_delegation_integration import L2DelegationIntegration | ||
|
||
load_dotenv() | ||
|
||
class ThalaAptosIntegration(L2DelegationIntegration): | ||
def __init__( | ||
self, | ||
integration_id: IntID, | ||
start_block: int, | ||
token_address: str, | ||
decimals: int, | ||
chain: Chain = Chain.APTOS, | ||
reward_multiplier: int = 1, | ||
): | ||
super().__init__( | ||
integration_id=integration_id, | ||
start_block=start_block, | ||
chain=chain, | ||
summary_cols=[SummaryColumn.THALA_SHARDS], | ||
reward_multiplier=reward_multiplier, | ||
) | ||
self.token_address = token_address | ||
self.decimals = str(decimals) | ||
self.thala_ts_location = "ts/thala_balances.ts" | ||
|
||
def get_l2_block_balances( | ||
self, cached_data: Dict[int, Dict[str, float]], blocks: List[int] | ||
) -> Dict[int, Dict[str, float]]: | ||
logging.info("Getting block data for Thala sUSDe LP...") | ||
# Ensure blocks are sorted smallest to largest | ||
block_data: Dict[int, Dict[str, float]] = {} | ||
sorted_blocks = sorted(blocks) | ||
|
||
# Populate block data from smallest to largest | ||
for block in sorted_blocks: | ||
# Check block_data first, then cached_data for previous block balances | ||
prev_block_user_balances = block_data.get(block - 1, cached_data.get(block - 1, {})) | ||
result = self.get_participants_data(block, prev_block_user_balances) | ||
|
||
# Store the balances | ||
block_data[block] = result['balances'] | ||
|
||
return block_data | ||
|
||
def get_participants_data(self, block, prev_block_user_balances=None): | ||
print("Getting participants data for block", block) | ||
try: | ||
response = subprocess.run( | ||
[ | ||
"ts-node", | ||
self.thala_ts_location, | ||
SUSDE_LPT_METADATA, | ||
str(self.decimals), | ||
str(block), | ||
json.dumps(prev_block_user_balances or {}), | ||
], | ||
capture_output=True, | ||
text=True, | ||
check=True | ||
) | ||
|
||
# Debug output | ||
print("TypeScript stdout:", response.stdout) | ||
print("TypeScript stderr:", response.stderr) | ||
|
||
try: | ||
result = json.loads(response.stdout) | ||
return result | ||
except json.JSONDecodeError as e: | ||
print(f"JSON Decode Error: {e}") | ||
print(f"Raw output: {response.stdout}") | ||
raise | ||
|
||
except subprocess.CalledProcessError as e: | ||
print(f"Process error: {e}") | ||
print(f"stderr: {e.stderr}") | ||
raise | ||
except Exception as e: | ||
print(f"Unexpected error: {e}") | ||
raise | ||
|
||
|
||
if __name__ == "__main__": | ||
example_integration = ThalaAptosIntegration( | ||
integration_id=IntID.THALA_SUSDE_LP, | ||
start_block=THALA_SUSDE_START_BLOCK, | ||
token_address=SUSDE_LPT_METADATA, | ||
decimals=8, | ||
chain=Chain.APTOS, | ||
reward_multiplier=5, | ||
) | ||
|
||
example_integration_output = example_integration.get_l2_block_balances( | ||
cached_data={}, blocks=list(range(THALA_SUSDE_START_BLOCK, THALA_SUSDE_START_BLOCK + 300)) | ||
) | ||
|
||
print("=" * 120) | ||
print("Run without cached data", example_integration_output) | ||
print("=" * 120, "\n" * 5) |
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,127 @@ | ||
import * as dotenv from "dotenv"; | ||
import { | ||
Aptos, | ||
AptosConfig, | ||
Network, | ||
WriteSetChangeWriteResource, | ||
isUserTransactionResponse, | ||
MoveResource, | ||
} from "@aptos-labs/ts-sdk"; | ||
|
||
dotenv.config(); | ||
|
||
const config = new AptosConfig({ network: Network.MAINNET }); | ||
// Aptos is the main entrypoint for all functions | ||
const client = new Aptos(config); | ||
|
||
const args = process.argv.slice(2); | ||
const SUSDE_LPT_METADATA = args[0]; | ||
const decimals = Number(args[1]); | ||
const block = Number(args[2]); | ||
const user_balances: Record<string, number> = new Proxy( | ||
args[3] ? JSON.parse(args[3]) : {}, | ||
{ | ||
get: (target, prop) => target[prop] || 0, | ||
} | ||
); | ||
|
||
type FungibleStoreResource = WriteSetChangeWriteResource & { | ||
data: MoveResource<FungibleStoreData>; | ||
}; | ||
|
||
type ObjectCoreResource = WriteSetChangeWriteResource & { | ||
data: MoveResource<ObjectCoreData>; | ||
}; | ||
|
||
type FungibleStoreData = { | ||
balance: string; | ||
metadata: { | ||
inner: string; | ||
}; | ||
}; | ||
|
||
type ObjectCoreData = { | ||
owner: string; | ||
}; | ||
|
||
async function getStrategy() { | ||
const block_data = await client.getBlockByHeight({ | ||
blockHeight: block, | ||
options: { | ||
withTransactions: true, | ||
}, | ||
}); | ||
|
||
if (!block_data) { | ||
throw new Error(`Block ${block} not found`); | ||
} | ||
|
||
if (!block_data.transactions) { | ||
throw new Error(`No transactions found in Block ${block}`); | ||
} | ||
|
||
const user_transactions = block_data.transactions.filter( | ||
isUserTransactionResponse | ||
); | ||
|
||
for (const transaction of user_transactions) { | ||
// First, collect all ObjectCore and LPT changes | ||
const objectCoreChanges = new Map<string, string>(); | ||
const lptChanges: Array<{ store: string; balance: string }> = []; | ||
|
||
// Collect all relevant changes | ||
for (const change of transaction.changes as WriteSetChangeWriteResource[]) { | ||
if (isObjectCoreChange(change)) { | ||
objectCoreChanges.set(change.address, change.data.data.owner); | ||
} else if (isLPTFungibleStoreChange(change)) { | ||
lptChanges.push({ | ||
store: change.address, | ||
balance: change.data.data.balance, | ||
}); | ||
} | ||
} | ||
|
||
// Process LPT changes after we have all the data | ||
for (const { store, balance } of lptChanges) { | ||
const userAddress = objectCoreChanges.get(store); | ||
if (userAddress) { | ||
user_balances[userAddress] = scaleDownByDecimals( | ||
Number(balance), | ||
decimals | ||
); | ||
} | ||
} | ||
} | ||
|
||
console.log( | ||
JSON.stringify({ | ||
balances: user_balances, | ||
}) | ||
); | ||
} | ||
|
||
function scaleDownByDecimals(value: number, decimals: number) { | ||
return value / 10 ** decimals; | ||
} | ||
|
||
function isLPTFungibleStoreChange( | ||
change: WriteSetChangeWriteResource | ||
): change is FungibleStoreResource { | ||
return ( | ||
change.type === "write_resource" && | ||
change.data.type === "0x1::fungible_asset::FungibleStore" && | ||
(change as FungibleStoreResource).data.data.metadata.inner === | ||
SUSDE_LPT_METADATA | ||
); | ||
} | ||
|
||
function isObjectCoreChange( | ||
change: WriteSetChangeWriteResource | ||
): change is ObjectCoreResource { | ||
return ( | ||
change.type === "write_resource" && | ||
change.data.type === "0x1::object::ObjectCore" | ||
); | ||
} | ||
|
||
const strategy = getStrategy().catch(console.error); |