Skip to content

Commit

Permalink
Merge pull request #44 from independenceee/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
independenceee authored Jul 12, 2024
2 parents 01ec995 + 3bd5730 commit 8e39e0d
Show file tree
Hide file tree
Showing 19 changed files with 514 additions and 184 deletions.
2 changes: 1 addition & 1 deletion frontend/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const nextConfig = {
// PREPROD NETWORK
BLOCKFROST_NETWORK_NAME_PREPROD: "Preprod",
BLOCKFROST_RPC_URL_PREPROD: "https://cardano-preprod.blockfrost.io/api/v0",
BLOCKFROST_PROJECT_API_KEY_PREPROD: "preprodpVntD7UGTviDa7Y7gqs7bcIZAdU5gcwr",
BLOCKFROST_PROJECT_API_KEY_PREPROD: "preprodxq4qzMjJbieRF8P24inEuVTZmwZDqHQ8",
KOIOS_RPC_URL_PREPROD: "https://preprod.koios.rest/api/v1",
NEXT_APP_BASE_URL_PREPROD: "https://preprod.dualtarget.vn/api/v1",
DUALTARGET_CONTRACT_ADDRESS_PREPROD:
Expand Down
36 changes: 31 additions & 5 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@blockfrost/blockfrost-js": "^5.5.0",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@emurgo/cardano-serialization-lib-nodejs": "^11.5.0",
"@hookform/resolvers": "^3.3.4",
"@minswap/sdk": "^0.2.2-beta",
"@mui/material": "^5.15.15",
Expand All @@ -35,7 +36,9 @@
"apexcharts": "^3.47.0",
"axios": "^1.6.8",
"binance-historical": "^1.5.20",
"cbor": "^9.0.2",
"cbor-x": "^1.5.8",
"cbor2": "^1.4.0",
"classnames": "^2.5.1",
"html-react-parser": "^5.1.10",
"i18next": "^23.10.1",
Expand Down
226 changes: 168 additions & 58 deletions frontend/src/app/(api)/api/history/reward/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { CardanoNetwork } from "@blockfrost/blockfrost-js/lib/types";
import { NextRequest } from "next/server";
import { BATCHER_FEE, DECIMAL_PLACES } from "~/constants";
import convertDatetime from "~/helpers/convert-datetime";
import convertInlineDatum from "~/helpers/convert-inline-datum";
import Blockfrost from "~/services/blockfrost";
import Koios from "~/services/koios";
import caculateDepositWithdraw from "~/utils/calculate-deposit-withdraw";
Expand All @@ -10,106 +13,213 @@ export async function GET(request: NextRequest) {

const page: string = searchParams.get("page") as string;
const pageSize: string = searchParams.get("page_size") as string;
const walletAddress: string = searchParams.get("wallet_address") as string;
const network: CardanoNetwork = searchParams.get("network") as CardanoNetwork;

const enviroment = readEnviroment({
network: network,
index: 0,
});
const adaPool: string = searchParams.get("ada_pool") as string;
const paymentAddress: string = searchParams.get("payment_address") as string;
const enviroment = readEnviroment({ network: network, index: 0 });

const poolId: string = enviroment.HADA_POOL_ID;
const stakeAddress: string = enviroment.DUALTARGET_STAKE_ADDRESS;
const smartcontractAddress: string = enviroment.DUALTARGET_CONTRACT_ADDRESS;

const koios = new Koios(enviroment.KOIOS_RPC_URL);

const blockfrost = new Blockfrost(
enviroment.BLOCKFROST_PROJECT_API_KEY as string,
network as CardanoNetwork,
);

const utxos = await Promise.all(
(await blockfrost.addressesTransactions(walletAddress))
.reverse()
.map(async function ({ tx_hash, block_time }) {
return {
block_time: block_time,
utxos: await blockfrost.txsUtxos(tx_hash),
};
}),
);

const accountsDelegation = await blockfrost.accountsDelegations(stakeAddress);

const specificTransaction = await blockfrost.txs(
accountsDelegation[accountsDelegation.length - 1].tx_hash,
);

const currentEpoch = await blockfrost.epochsLatest();

// TODO: 5 QUERY
const addrTsx = (
await Promise.all(
Array.from({ length: 5 }, async function (_, index: number) {
return await blockfrost.addressesTransactions(smartcontractAddress, {
order: "desc",
count: 100,
page: index + 1,
});
}),
)
).flat();

let results: any = [];

for (let index = currentEpoch.epoch; index >= currentEpoch.epoch - 10; index--) {
const epochInfomation = await koios.epochInfomation({ epochNo: index });
for (let epoch = currentEpoch.epoch; epoch >= currentEpoch.epoch - 7; epoch--) {
const { start_time, end_time } = await koios.epochInfomation({ epochNo: epoch });

const addrTsxFilter = addrTsx.filter(function ({ block_time }, index: number) {
return block_time >= start_time && block_time <= end_time;
});

// Đọc các UTXO của smartcontract trong khoảng 1 epoch
const txsUtxos = await Promise.all(
addrTsxFilter.map(async function ({ tx_hash }) {
return await blockfrost.txsUtxos(tx_hash);
}),
);

// Deposit(+): Output là địa chỉ smc
const depositUtxos = await Promise.all(
txsUtxos.map(async function (txsUtxo) {
const outputs = await Promise.all(
txsUtxo.outputs.map(async function (output) {
const datum = await convertInlineDatum({
inlineDatum: output.inline_datum!,
});
if (
output.address === smartcontractAddress &&
output.inline_datum !== null &&
datum?.fields[0].bytes === paymentAddress
) {
return output;
}
return null;
}),
);
return outputs.filter((output) => output !== null);
}),
);

// Withdraw(-): Input là địa chỉ của smc
const withdrawUtxos = await Promise.all(
txsUtxos.map(async function (txsUtxo) {
const inputs = await Promise.all(
txsUtxo.inputs.map(async function (input) {
const datum = await convertInlineDatum({
inlineDatum: input.inline_datum!,
});
if (
input.address === smartcontractAddress &&
!input.reference_script_hash &&
input.inline_datum !== null &&
datum?.fields[0].bytes === paymentAddress
) {
return input;
}
return null;
}),
);
return inputs.filter((input) => input !== null);
}),
);
// Read datum inputs

const amountDeposit = depositUtxos
.map(function (depositUtxo) {
return depositUtxo.reduce(function (amount, outputs) {
if (outputs && outputs.amount) {
return (
amount +
Number(
outputs.amount.reduce(function (total, { unit, quantity }) {
if (unit === "lovelace") {
return total + Number(quantity);
}
return total;
}, 0),
)
);
}

return amount;
}, 0);
})
.reduce(function (balance, current) {
return balance + current;
});

const amountWithdraw = withdrawUtxos
.map(function (depositUtxo) {
return depositUtxo.reduce(function (amount, inputs) {
if (inputs && inputs.amount) {
return (
amount +
Number(
inputs.amount.reduce(function (total, { unit, quantity }) {
if (unit === "lovelace") {
return total + Number(quantity);
}
return total;
}, 0),
)
);
}
return amount;
}, 0);
})
.reduce(function (balance, current) {
return balance + current;
});

const amountStake: number = await koios.poolDelegatorsHistory({
poolId: poolId,
stakeAddress: stakeAddress,
epochNo: index,
epochNo: epoch,
});

const accountRewards: number = await koios.accountRewards({
stakeAddress,
epochNo: index,
epochNo: epoch,
});

if (index === currentEpoch.epoch) {
const amountDepositWithdraw: number = await caculateDepositWithdraw({
utxos: utxos,
address: smartcontractAddress,
endTime: epochInfomation.start_time,
startTimeStake: specificTransaction.block_time,
});
console.log(epochInfomation.start_time, amountDepositWithdraw);

const ROS: number = amountDepositWithdraw / amountStake;
results.push({
amount: -amountDeposit + amountWithdraw,
epoch: epoch,
adaPool: adaPool,
amountReward: accountRewards,
amountStake: amountStake,
});
}

results.push({
epoch: index,
amount: +amountDepositWithdraw.toFixed(5),
rewards: +(!isNaN(accountRewards * ROS) ? accountRewards * ROS : 0).toFixed(5),
let caculateAdaRewards = [];
let caculateAdaRewardTemp = 0;
for (let index = 1; index < results.length; index++) {
if (index === 1) {
caculateAdaRewardTemp +=
Number(results[index - 1].adaPool) +
Number(results[index - 1].amount / DECIMAL_PLACES) +
Number(results[index].amount / DECIMAL_PLACES);
}
caculateAdaRewardTemp += Number(results[index].amount / DECIMAL_PLACES);

const reward =
(caculateAdaRewardTemp * Number(results[index - 1].amountReward)) /
Number(results[index - 1].amountStake);

if (
results[index - 1].epoch === currentEpoch.epoch &&
results[index - 1].epoch === currentEpoch.epoch - 1
) {
caculateAdaRewards.push({
epoch: results[index - 1].epoch,
amount: caculateAdaRewardTemp.toFixed(5),
rewards: "-",
status: "Distributed",
});
}

const amountDepositWithdraw: number = await caculateDepositWithdraw({
utxos: utxos,
address: smartcontractAddress,
endTime: epochInfomation.end_time,
startTimeStake: specificTransaction.block_time,
});
const ROS: number = amountDepositWithdraw / amountStake;

if (amountDepositWithdraw !== 0) {
results.push({
epoch: index + 3,
amount: +amountDepositWithdraw.toFixed(5),
rewards: +(!isNaN(accountRewards * ROS) ? accountRewards * ROS : 0).toFixed(5),
} else {
caculateAdaRewards.push({
epoch: results[index - 1].epoch,
amount: caculateAdaRewardTemp.toFixed(5),
rewards: reward.toFixed(5),
status: "Distributed",
});
}
}

const totalPage = Math.ceil(results.length / Number(pageSize));
const histories = [...results].slice(
const totalPage = Math.ceil(caculateAdaRewards.length / Number(pageSize));
const histories = [...caculateAdaRewards].slice(
(Number(page) - 1) * Number(pageSize),
Number(page) * Number(pageSize),
);

console.log(histories);

return Response.json({
totalPage,
histories,
totalItems: results.length,
totalItems: caculateAdaRewards.length,
});
}
Loading

0 comments on commit 8e39e0d

Please sign in to comment.