Skip to content
Open
7 changes: 7 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ assert.ok(
ARBITRUM_SEPOLIA_PRIVATE_KEY,
"no ARBITRUM_SEPOLIA_PRIVATE_KEY in .env"
);
const BASE_SEPOLIA_PRIVATE_KEY = process.env.BASE_SEPOLIA_PRIVATE_KEY;
assert.ok(BASE_SEPOLIA_PRIVATE_KEY, "no BASE_SEPOLIA_PRIVATE_KEY in .env");
const AVALANCHE_PRIVATE_KEY = process.env.AVALANCHE_PRIVATE_KEY;
assert.ok(AVALANCHE_PRIVATE_KEY, "no AVALANCHE_PRIVATE_KEY in .env");
const AVALANCHE_FUJI_PRIVATE_KEY = process.env.AVALANCHE_FUJI_PRIVATE_KEY;
Expand Down Expand Up @@ -50,6 +52,11 @@ const config: HardhatUserConfig = {
url: "https://sepolia-rollup.arbitrum.io/rpc",
accounts: [ARBITRUM_SEPOLIA_PRIVATE_KEY],
},
baseSepolia: {
chainId: 84532,
url: "https://sepolia.base.org",
accounts: [BASE_SEPOLIA_PRIVATE_KEY],
},
avalanche: {
chainId: 43114,
url: "https://api.avax.network/ext/bc/C/rpc",
Expand Down
30 changes: 30 additions & 0 deletions scripts/callFunction_contributorHandler_sendPayments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { initExecute } from "./utils/callFunctionUtils";
import { getLogger, Logger } from "../src/lib/logger";
import { getContracts } from "../src/lib/contracts";

const logger: Logger = getLogger(false);

async function main() {
logger.log("Running script to call ContributorHandler.sendPayments()");

try {
const { signer, chainId, provider } = await initExecute();
const { contributorHandler } = getContracts(chainId, provider);

logger.log("Executing sendPayments transaction...");

const tx = await contributorHandler.connect(signer).sendPayments();

logger.log(`Transaction hash: ${tx.hash}`);
logger.log("Waiting for transaction confirmation...");

const receipt = await tx.wait();
logger.log(`Transaction confirmed in block ${receipt.blockNumber}`);
logger.log("sendPayments completed successfully!");
} catch (error) {
logger.log("Error during sendPayments:", error);
process.exit(1);
}
}

main().catch(logger.error);
30 changes: 30 additions & 0 deletions scripts/callFunction_feeDistributor_bridgedGmxReceived.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { initExecute } from "./utils/callFunctionUtils";
import { getLogger, Logger } from "../src/lib/logger";
import { getContracts } from "../src/lib/contracts";

const logger: Logger = getLogger(false);

async function main() {
logger.log("Running script to call FeeDistributor.bridgedGmxReceived()");

try {
const { signer, chainId, provider } = await initExecute();
const { feeDistributor } = getContracts(chainId, provider);

logger.log("Executing bridgedGmxReceived transaction...");

const tx = await feeDistributor.connect(signer).bridgedGmxReceived();

logger.log(`Transaction hash: ${tx.hash}`);
logger.log("Waiting for transaction confirmation...");

const receipt = await tx.wait();
logger.log(`Transaction confirmed in block ${receipt.blockNumber}`);
logger.log("bridgedGmxReceived completed successfully!");
} catch (error) {
logger.log("Error during bridgedGmxReceived:", error);
process.exit(1);
}
}

main().catch(logger.error);
105 changes: 105 additions & 0 deletions scripts/callFunction_feeDistributor_depositReferralRewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import {
loadDistributionData,
cleanupFiles,
initExecute,
} from "./utils/callFunctionUtils";
import { WNT_PRICE_KEY } from "../src/lib/keys/keys";
import { DISTRIBUTION_ID } from "../src/domain/fee/feeDistributionUtils";
import { referralRewardsCalls } from "../src/domain/fee/feeDistributionService";
import { getLogger, Logger } from "../src/lib/logger";
import { getContracts } from "../src/lib/contracts";

const logger: Logger = getLogger(false);

async function executeTransaction(
signer: SignerWithAddress,
callData: { to: string; data: string },
index: number,
logger: Logger
) {
const tx = await signer.sendTransaction({
to: callData.to,
data: callData.data,
});

logger.log(`Transaction hash: ${tx.hash}`);
logger.log("Waiting for confirmation...");

const receipt = await tx.wait();
logger.log(`Transaction confirmed in block ${receipt.blockNumber}`);
}

async function main() {
logger.log("Running script to call FeeDistributor.depositReferralRewards()");

try {
const { signer, chainId, provider } = await initExecute();
const { dataStore, feeDistributorVault, feeDistributor, wnt, esGmx } =
getContracts(chainId, provider);

const [wntPrice, distributionData] = await Promise.all([
dataStore.getUint(WNT_PRICE_KEY),
loadDistributionData(),
]);
logger.log("Loaded saved data");

if (chainId !== distributionData.chainId) {
throw new Error(
`Chosen network (${chainId}) does not match network in save data (${distributionData.chainId})`
);
}

logger.log("Generating referral rewards calls...");
const calls = await referralRewardsCalls({
logger: logger,
feeDistributorVault: feeDistributorVault.address,
wntPrice: wntPrice,
feeDistributor: feeDistributor,
wnt: wnt,
esGmx: esGmx,
data: distributionData,
distributionId: DISTRIBUTION_ID,
useBatchSize: true,
});

const startIndex = Number(process.env.RESUME_INDEX) || 0;

logger.log(`Total calls to execute: ${calls.length - startIndex}`);

for (let i = startIndex; i < calls.length; i++) {
try {
const call = calls[i];
if (!call) {
throw new Error(`Call at index ${i} is undefined`);
}
logger.log(
`Executing transaction ${i + 1} of ${calls.length} at index ${i}...`
);
await executeTransaction(signer, call, i, logger);
} catch (error) {
logger.log(
`Error executing transaction ${i + 1} of ${
calls.length
} at index ${i}`,
error
);
logger.log(
"\n Check block explorer to confirm the transaction failed and in .env include the RESUME_INDEX environment variable with the index at which to resume, then rerun the script"
);
process.exit(1);
}
}

logger.log("\nAll transactions completed successfully!");
logger.log(`Total transactions executed: ${calls.length - startIndex}`);
logger.log("\nCleaning up temporary files...");
await cleanupFiles();
logger.log("Fee distribution process completed!");
} catch (error) {
logger.log("Error during deposit referral rewards:", error);
process.exit(1);
}
}

main().catch(logger.error);
134 changes: 134 additions & 0 deletions scripts/callFunction_feeDistributor_distribute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {
ensureDataDir,
saveDistributionData,
initExecute,
} from "./utils/callFunctionUtils";
import {
GMX_PRICE_KEY,
MAX_REFERRAL_REWARDS_ESGMX_AMOUNT_KEY,
} from "../src/lib/keys/keys";
import { RELATIVE_PERIOD_NAME } from "../src/domain/fee/feeDistributionUtils";
import {
processPeriodV1,
processPeriodV2,
getDistributionData,
} from "../src/domain/fee/feeDistributionService";
import { getLogger, Logger } from "../src/lib/logger";
import { getContracts } from "../src/lib/contracts";
import {
formatAmount,
USD_DECIMALS,
GMX_DECIMALS,
PRICE_DECIMALS,
} from "../src/lib/number";

const logger: Logger = getLogger(false);

async function main() {
logger.log(
"Running script to retrieve fee and referral reward data and call FeeDistributor.distribute()"
);

try {
await ensureDataDir();

if (process.env.RESUME_INDEX) {
throw new Error(
"Remove RESUME_INDEX environment variable from .env and try again"
);
}
const sendTransactionStr = process.env.SEND_TRANSACTION;
if (!sendTransactionStr) {
throw new Error("SEND_TRANSACTION environment variable not provided");
}
if (sendTransactionStr !== "true" && sendTransactionStr !== "false") {
throw new Error(
'SEND_TRANSACTION environment must equal "true" or "false"'
);
}
const sendTransaction = sendTransactionStr === "true";

const { signer, chainId, provider } = await initExecute();
const { dataStore, feeDistributor } = getContracts(chainId, provider);

logger.log("Fetching prices from DataStore...");
const [gmxPrice, maxEsGmxRewards] = await Promise.all([
dataStore.getUint(GMX_PRICE_KEY),
dataStore.getUint(MAX_REFERRAL_REWARDS_ESGMX_AMOUNT_KEY),
]);

logger.log(`GMX Price: ${formatAmount(gmxPrice, PRICE_DECIMALS, 2)}`);
logger.log(
`Max esGMX Rewards: ${formatAmount(maxEsGmxRewards, GMX_DECIMALS, 2)}`
);

logger.log("Processing V1 and V2 fees...");
const [feesV1Usd, feesV2Usd] = await Promise.all([
processPeriodV1(RELATIVE_PERIOD_NAME, chainId),
processPeriodV2(RELATIVE_PERIOD_NAME, chainId),
]);

logger.log(`V1 Fees: ${formatAmount(feesV1Usd, USD_DECIMALS, 2)}`);
logger.log(`V2 Fees: ${formatAmount(feesV2Usd, USD_DECIMALS, 2)}`);

logger.log("Calculating distribution data...");
const distributionData = await getDistributionData(
logger,
chainId,
RELATIVE_PERIOD_NAME,
gmxPrice,
maxEsGmxRewards
);

await saveDistributionData(distributionData);

if (sendTransaction) {
logger.log("Executing distribute transaction...");

const tx = await feeDistributor
.connect(signer)
.distribute(
distributionData.totalRebateUsd,
distributionData.totalEsGmxRewards,
feesV1Usd,
feesV2Usd
);

logger.log(`Transaction hash: ${tx.hash}`);
logger.log("Waiting for transaction confirmation...");

const receipt = await tx.wait();
logger.log(`Transaction confirmed in block ${receipt.blockNumber}`);
logger.log("Distribution completed successfully!");
} else {
logger.log("SEND_TRANSACTION is false - skipping transaction execution");
logger.log("Distribution data has been saved for later processing");
}

logger.log("\nSummary");
logger.log(
`Total Referral Volume: ${distributionData.totalReferralVolume}`
);
logger.log(
`Total Rebate USD: ${formatAmount(
distributionData.totalRebateUsd,
USD_DECIMALS,
2
)}`
);
logger.log(
`Total esGMX Rewards: ${formatAmount(
distributionData.totalEsGmxRewards,
GMX_DECIMALS,
2
)}`
);
logger.log(`Affiliates Count: ${distributionData.affiliates.length}`);
logger.log(`Referrals Count: ${distributionData.referrals.length}`);
} catch (error) {
logger.log("Error during distribution:", error);
process.exit(1);
}
}

main().catch(logger.error);
30 changes: 30 additions & 0 deletions scripts/callFunction_feeDistributor_initiateDistribute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { initExecute } from "./utils/callFunctionUtils";
import { getLogger, Logger } from "../src/lib/logger";
import { getContracts } from "../src/lib/contracts";

const logger: Logger = getLogger(false);

async function main() {
logger.log("Running script to call FeeDistributor.initiateDistribute()");

try {
const { signer, chainId, provider } = await initExecute();
const { feeDistributor } = getContracts(chainId, provider);

logger.log("Executing initiateDistribute transaction...");

const tx = await feeDistributor.connect(signer).initiateDistribute();

logger.log(`Transaction hash: ${tx.hash}`);
logger.log("Waiting for transaction confirmation...");

const receipt = await tx.wait();
logger.log(`Transaction confirmed in block ${receipt.blockNumber}`);
logger.log("initiateDistribute completed successfully!");
} catch (error) {
logger.log("Error during initiateDistribute:", error);
process.exit(1);
}
}

main().catch(logger.error);
2 changes: 1 addition & 1 deletion scripts/createTask_contributorHandler_sendPayments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const main = async () => {
execAbi: contributorHandler.interface.format("json") as string,
trigger: {
type: TriggerType.CRON,
cron: "0 0 28 * *",
cron: "1 0 28 * *",
},
name: "ContributorHandler.sendPayments()",
dedicatedMsgSender: true,
Expand Down
Loading