Basic state loading
This commit is contained in:
parent
4715e44373
commit
9344332788
|
@ -3,17 +3,31 @@
|
|||
*/
|
||||
|
||||
import BN from "bn.js";
|
||||
import { LittleEndianByteInput } from "@secata-public/bitmanipulation-ts";
|
||||
import { BlockchainAddress, StateBytes } from "@partisiablockchain/abi-client";
|
||||
import { TransactionFailedError } from "../client/TransactionApi";
|
||||
import { PutTransactionWasSuccessful } from "../client/TransactionData";
|
||||
import { ShardedClient } from "../client/ShardedClient";
|
||||
import { RouterState, deserializeRouterState } from "../abi/SwapRouter";
|
||||
import { LiquiditySwapContractState, deserializeLiquiditySwapContractState } from "../abi/LiquiditySwapContract";
|
||||
import { TokenState, deserializeTokenState } from "../abi/TokenV1";
|
||||
import { TokenBalance, LiquiditySwapContractState, deserializeLiquiditySwapContractState } from "../abi/LiquiditySwapLock";
|
||||
import { TokenState as TokenStateV1, deserializeTokenState as deserializeTokenStateV1 } from "../abi/TokenV1";
|
||||
import { TokenState as TokenStateV2, deserializeTokenState as deserializeTokenStateV2 } from "../abi/TokenV2";
|
||||
import { NETWORK } from "../constant";
|
||||
import { AvlClient } from "../client/AvlClient";
|
||||
|
||||
// UI constants
|
||||
const TOKEN_LIST = <Element>document.querySelector("#token-list");
|
||||
const EXCHANGE_RATE_LIST = <Element>document.querySelector("#rate-list");
|
||||
|
||||
|
||||
// Logic
|
||||
|
||||
type ContractType = "token_v1" | "token_v2" | "swap_lock_v1"
|
||||
|
||||
interface ContractState {
|
||||
latest_state: TokenState | LiquiditySwapContractState | null;
|
||||
latest_state: TokenStateV1 | TokenStateV2 | null;
|
||||
swaps: BlockchainAddress[] | null,
|
||||
type: ContractType | null,
|
||||
}
|
||||
|
||||
const ROUTERS: BlockchainAddress[] = [BlockchainAddress.fromString("02f8eb18e09dfe6797880c952527747202560338bf")];
|
||||
|
@ -25,15 +39,15 @@ const TOKENS: Record<BlockchainAddressKey, ContractState> = {};
|
|||
const SWAPS: Record<BlockchainAddressKey, ContractState> = {};
|
||||
|
||||
const SHARDED_CLIENT: ShardedClient = new ShardedClient(NETWORK.node_base_url, NETWORK.network_shards);
|
||||
const AVL_CLIENT:AvlClient = new AvlClient(NETWORK .node_base_url, NETWORK.network_shards);;
|
||||
|
||||
interface RawContractData {
|
||||
state: { data: string };
|
||||
}
|
||||
|
||||
function get_contract_state<T>(contractAddress: BlockchainAddress, deserialize: (state_bytes: StateBytes) => T): Promise<T> {
|
||||
return SHARDED_CLIENT
|
||||
.getContractData<RawContractData>(contractAddress.asString())
|
||||
.then((contract) => {
|
||||
async function get_contract_state<T>(contractAddress: BlockchainAddress, deserialize: (state_bytes: StateBytes) => T): Promise<T> {
|
||||
const contract = await SHARDED_CLIENT.getContractData<RawContractData>(contractAddress.asString());
|
||||
|
||||
if (contract == null) {
|
||||
throw new Error("Could not find data for contract");
|
||||
}
|
||||
|
@ -42,9 +56,115 @@ function get_contract_state<T>(contractAddress: BlockchainAddress, deserialize:
|
|||
const stateBuffer = Buffer.from(contract.serializedContract.state.data, "base64");
|
||||
|
||||
return deserialize({ state: stateBuffer });
|
||||
});
|
||||
}
|
||||
|
||||
function address_to_url(address: BlockchainAddress): string {
|
||||
return `${NETWORK.browser_base_url}/contracts/${address.asString()}`;
|
||||
}
|
||||
|
||||
function ui_add_token(tokenState: TokenStateV1 | TokenStateV2, address: BlockchainAddress) {
|
||||
const spanFrom = document.createElement("div");
|
||||
spanFrom.innerHTML = `
|
||||
<form class="pure-form" onSubmit="return false;">
|
||||
<input
|
||||
class="pure-button pure-button-primary"
|
||||
id="private-key-connect-btn"
|
||||
type="submit"
|
||||
value="From" />
|
||||
</form>
|
||||
`;
|
||||
const spanTo = document.createElement("div");
|
||||
spanTo.innerHTML = `
|
||||
<form class="pure-form" onSubmit="return false;">
|
||||
<input
|
||||
class="pure-button pure-button-primary"
|
||||
id="private-key-connect-btn"
|
||||
type="submit"
|
||||
value="To" />
|
||||
</form>
|
||||
`;
|
||||
const spanSymbol= document.createElement("a");
|
||||
spanSymbol.innerText = tokenState.symbol;
|
||||
spanSymbol.title = tokenState.name;
|
||||
spanSymbol.href = address_to_url(address);
|
||||
const spanAmount = document.createElement("div");
|
||||
spanAmount.innerText = "Login to view";
|
||||
TOKEN_LIST.append(spanFrom);
|
||||
TOKEN_LIST.append(spanTo);
|
||||
TOKEN_LIST.append(spanSymbol);
|
||||
TOKEN_LIST.append(spanAmount);
|
||||
}
|
||||
|
||||
async function get_current_liquidity(swapAddress: BlockchainAddress): Promise<TokenBalance> {
|
||||
const SWAP_CONTRACT_BALANCES_TREE_ID = 0;
|
||||
const dataBuffer = await AVL_CLIENT.getContractStateAvlValue(
|
||||
swapAddress.asString(),
|
||||
SWAP_CONTRACT_BALANCES_TREE_ID,
|
||||
swapAddress.asBuffer(),
|
||||
);
|
||||
|
||||
if (dataBuffer === undefined) {
|
||||
throw new Error("Contract was not correctly initialized");
|
||||
}
|
||||
|
||||
const reader = new LittleEndianByteInput(dataBuffer);
|
||||
|
||||
return {
|
||||
aTokens: reader.readUnsignedBigInteger(16),
|
||||
bTokens: reader.readUnsignedBigInteger(16),
|
||||
liquidityTokens: reader.readUnsignedBigInteger(16),
|
||||
}
|
||||
}
|
||||
|
||||
const RATE_DECIMALS = new BN(10000);
|
||||
|
||||
async function get_current_exchange_rate(swapAddress: BlockchainAddress): Promise<BN> {
|
||||
const liquidity: TokenBalance = await get_current_liquidity(swapAddress);
|
||||
const result = liquidity.aTokens.mul(RATE_DECIMALS).div(liquidity.bTokens);
|
||||
console.log(`${liquidity.aTokens}.mul(${RATE_DECIMALS}).div(${liquidity.bTokens}) = ${result}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
function ui_add_swap(swapAddress: BlockchainAddress) {
|
||||
const rateElement = document.createElement("li");
|
||||
rateElement.id = "C"+swapAddress.asString();
|
||||
rateElement.innerText = swapAddress.asString();
|
||||
EXCHANGE_RATE_LIST.append(rateElement);
|
||||
}
|
||||
|
||||
async function ui_update_swap(swapState: LiquiditySwapContractState, swapAddress: BlockchainAddress) {
|
||||
// Calculate rate
|
||||
|
||||
const infoA = TOKENS[swapState.tokenBalances.tokenAAddress.asString()];
|
||||
const infoB = TOKENS[swapState.tokenBalances.tokenBAddress.asString()];
|
||||
|
||||
const symbolA = infoA.latest_state == null ? "???" : infoA.latest_state.symbol;
|
||||
const symbolB = infoB.latest_state == null ? "???" : infoB.latest_state.symbol;
|
||||
|
||||
const rateBsForA: BN = await get_current_exchange_rate(swapAddress);
|
||||
|
||||
//
|
||||
const rateElement = <Element>document.querySelector("#C"+swapAddress.asString());
|
||||
// TODO: Liquidity information
|
||||
rateElement.innerHTML = `${RATE_DECIMALS} ${symbolA} = ${rateBsForA} ${symbolB} (<a href="${address_to_url(swapAddress)}">Contract</a>)`;
|
||||
}
|
||||
|
||||
function update_swap_contract_info(){
|
||||
for (const swapAddressStr in SWAPS) {
|
||||
const swapAddress = BlockchainAddress.fromString(swapAddressStr);
|
||||
get_contract_state(swapAddress, deserializeLiquiditySwapContractState).then(state => ui_update_swap(state, swapAddress));
|
||||
}
|
||||
}
|
||||
|
||||
async function get_token_state(tokenAddress: BlockchainAddress): Promise<TokenStateV1 | TokenStateV2> {
|
||||
try {
|
||||
return await get_contract_state(tokenAddress, deserializeTokenStateV1);
|
||||
} catch {
|
||||
// Pass
|
||||
}
|
||||
|
||||
return await get_contract_state(tokenAddress, deserializeTokenStateV2);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
for (let router of ROUTERS) {
|
||||
|
@ -52,16 +172,24 @@ function setup() {
|
|||
get_contract_state(router, deserializeRouterState).then((state) => {
|
||||
console.log(state);
|
||||
|
||||
for (let swapInfo of state.swapContracts) {
|
||||
SWAPS[swapInfo.swapAddress.asString()] = { latest_state: null };
|
||||
TOKENS[swapInfo.tokenAAddress.asString()] = { latest_state: null };
|
||||
TOKENS[swapInfo.tokenBAddress.asString()] = { latest_state: null };
|
||||
|
||||
// TODO: Deduplicate tokens
|
||||
get_contract_state(swapInfo.swapAddress, deserializeLiquiditySwapContractState).then(console.log);
|
||||
get_contract_state(swapInfo.tokenAAddress, deserializeTokenState).then(console.log);
|
||||
get_contract_state(swapInfo.tokenBAddress, deserializeTokenState).then(console.log);
|
||||
for (const swapInfo of state.swapContracts) {
|
||||
TOKENS[swapInfo.tokenAAddress.asString()] = { latest_state: null, swaps: null, type: null };
|
||||
TOKENS[swapInfo.tokenBAddress.asString()] = { latest_state: null, swaps: null, type: null };
|
||||
SWAPS[swapInfo.swapAddress.asString()] = { latest_state: null, swaps: [swapInfo.tokenAAddress, swapInfo.tokenBAddress], type: null };
|
||||
ui_add_swap(swapInfo.swapAddress);
|
||||
}
|
||||
|
||||
for (const tokenAddressStr in TOKENS) {
|
||||
const tokenAddress = BlockchainAddress.fromString(tokenAddressStr);
|
||||
get_token_state(tokenAddress).then(state => {
|
||||
TOKENS[tokenAddress.asString()].type = "token_v1";
|
||||
TOKENS[tokenAddress.asString()].latest_state = state;
|
||||
ui_add_token(state, tokenAddress);
|
||||
});
|
||||
}
|
||||
|
||||
update_swap_contract_info();
|
||||
setInterval(update_swap_contract_info, 30*1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,14 @@
|
|||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
#token-list {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto 1fr;
|
||||
grid-gap: 1em;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
|
@ -63,30 +71,14 @@
|
|||
<div id="overview">
|
||||
<h2>Token Overview</h2>
|
||||
<div id="token-list">
|
||||
<span>
|
||||
<form class="pure-form" onSubmit="return false;">
|
||||
<input
|
||||
class="pure-button pure-button-primary"
|
||||
id="private-key-connect-btn"
|
||||
type="submit"
|
||||
value="From" />
|
||||
</form>
|
||||
</span>
|
||||
<span>
|
||||
<form class="pure-form" onSubmit="return false;">
|
||||
<input
|
||||
class="pure-button pure-button-primary"
|
||||
id="private-key-connect-btn"
|
||||
type="submit"
|
||||
value="To" />
|
||||
</form>
|
||||
</span>
|
||||
<span>
|
||||
<img todo></img>
|
||||
</span>
|
||||
<span>
|
||||
Owned
|
||||
</span>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div>Symbol</div>
|
||||
<div>Owned Amount</div>
|
||||
</div>
|
||||
|
||||
<h2>Exchange Rates</h2>
|
||||
<ul id="rate-list">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user